import { createHash } from "node:crypto";
import { NextResponse } from "next/server";
import { createClient as createSupabaseClient } from "@supabase/supabase-js";
import { createAdminClient } from "@/lib/supabase-admin";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const revalidate = 0;

export async function POST(request: Request) {
  try {
    const authHeader = String(request.headers.get("authorization") || "");
    const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7).trim() : "";

    const body = (await request.json().catch(() => null)) as
      | {
          slug?: unknown;
          password?: unknown;
          portalToken?: unknown;
          codigo?: unknown;
        }
      | null;

    const slug = typeof body?.slug === "string" ? body.slug.trim() : "";
    const password = typeof body?.password === "string" ? body.password : "";
    const portalToken = typeof body?.portalToken === "string" ? body.portalToken.trim() : "";

    if (!slug || password.length < 8) {
      return NextResponse.json({ error: "Informe uma nova senha com pelo menos 8 caracteres." }, { status: 400 });
    }

    const admin = createAdminClient();

    /*
      O link que o próprio sistema mandou por e-mail (password-reset/request).

      O código vale uma vez e por uma hora. Ele é queimado ANTES de trocar a
      senha (a troca só segue se esta chamada foi a que o queimou), então dois
      envios ao mesmo tempo não trocam a senha duas vezes. Depois da troca, os
      outros links pendentes do cliente deixam de valer e as sessões abertas
      do portal são encerradas: quem pediu nova senha pode estar tirando
      alguém de dentro da conta.
    */
    const codigo = typeof body?.codigo === "string" ? body.codigo.trim() : "";
    if (codigo) {
      const linkInvalido = () =>
        NextResponse.json({ error: "Link invalido ou expirado. Peça um novo em \"Esqueci minha senha\"." }, { status: 401 });
      const codigoHash = createHash("sha256").update(codigo).digest("hex");
      const { data: registro } = await admin
        .from("client_portal_codes")
        .select("id,store_id,client_id,expira_em,usado_em")
        .eq("codigo_hash", codigoHash)
        .eq("tipo", "redefinir_senha")
        .maybeSingle();
      if (!registro?.id || registro.usado_em || new Date(String(registro.expira_em)).getTime() < Date.now()) {
        return linkInvalido();
      }

      const { data: loja } = await admin.from("profiles").select("id").eq("slug", slug).maybeSingle();
      if (!loja?.id || String(loja.id) !== String(registro.store_id)) return linkInvalido();

      const { data: cliente } = await admin
        .from("clients")
        .select("id,email,portal_enabled")
        .eq("id", registro.client_id)
        .eq("user_id", loja.id)
        .maybeSingle();
      const emailDoCliente = String(cliente?.email || "").trim().toLowerCase();
      if (!cliente?.id || !emailDoCliente || cliente.portal_enabled === false) return linkInvalido();

      const agora = new Date().toISOString();
      const { data: queimado } = await admin
        .from("client_portal_codes")
        .update({ usado_em: agora })
        .eq("id", registro.id)
        .is("usado_em", null)
        .select("id")
        .maybeSingle();
      if (!queimado?.id) return linkInvalido();

      const { data, error } = await admin.rpc("client_portal_set_password", {
        p_slug: slug,
        p_email: emailDoCliente,
        p_password: password,
      });
      if (error) {
        return NextResponse.json({ error: error.message || "Nao foi possivel atualizar a senha do portal." }, { status: 400 });
      }

      await admin
        .from("client_portal_codes")
        .update({ usado_em: agora })
        .eq("client_id", cliente.id)
        .eq("tipo", "redefinir_senha")
        .is("usado_em", null);
      await admin
        .from("client_portal_sessions")
        .update({ revoked_at: agora })
        .eq("client_id", cliente.id)
        .is("revoked_at", null);

      return NextResponse.json({ ok: true, email: emailDoCliente, result: data || null });
    }

    if (portalToken) {
      const { data: sessionData, error: sessionError } = await admin.rpc("client_portal_get_session", {
        p_slug: slug,
        p_session_token: portalToken,
      });
      const sessionPayload = (sessionData || null) as { client?: { email?: string | null } } | null;
      const sessionEmail = String(sessionPayload?.client?.email || "").trim().toLowerCase();

      if (sessionError || !sessionEmail) {
        return NextResponse.json({ error: "Link de acesso invalido ou expirado." }, { status: 401 });
      }

      const { data, error } = await admin.rpc("client_portal_set_password", {
        p_slug: slug,
        p_email: sessionEmail,
        p_password: password,
      });

      if (error) {
        return NextResponse.json({ error: error.message || "Nao foi possivel atualizar a senha do portal." }, { status: 400 });
      }

      return NextResponse.json({
        ok: true,
        email: sessionEmail,
        result: data || null,
      });
    }

    if (!token) {
      return NextResponse.json({ error: "Sessao de recuperacao invalida." }, { status: 401 });
    }

    const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
    const anon = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

    if (!url || !anon) {
      return NextResponse.json({ error: "Configuracao do Supabase ausente." }, { status: 500 });
    }

    const supabase = createSupabaseClient(url, anon);
    const {
      data: { user },
      error: userError,
    } = await supabase.auth.getUser(token);

    if (userError || !user?.email) {
      return NextResponse.json({ error: "Sessao de recuperacao invalida ou expirada." }, { status: 401 });
    }

    const { data, error } = await admin.rpc("client_portal_set_password", {
      p_slug: slug,
      p_email: user.email.trim().toLowerCase(),
      p_password: password,
    });

    if (error) {
      return NextResponse.json({ error: error.message || "Nao foi possivel atualizar a senha do portal." }, { status: 400 });
    }

    return NextResponse.json({
      ok: true,
      email: user.email,
      result: data || null,
    });
  } catch (error) {
    const message =
      typeof error === "object" && error && "message" in error && typeof error.message === "string"
        ? error.message
        : "Nao foi possivel concluir a redefinicao de senha.";

    return NextResponse.json({ error: message }, { status: 500 });
  }
}
