import { createHash, randomBytes } from "node:crypto";
import { NextResponse } from "next/server";
import { resolvePublicOrigin } from "@/lib/request-origin";
import { createAdminClient } from "@/lib/supabase-admin";
import { emailDaLojaConfigurado, enviarEmailDaLoja, montarEmailDaLoja } from "@/lib/email-da-loja";

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

/* O link vale uma hora e uma vez só. */
const VALIDADE_DO_LINK_MS = 60 * 60 * 1000;
/* Freios: o mesmo cliente pede no máximo 3 vezes por hora; o mesmo endereço de
   rede, 10. Passou disso, a resposta continua igual — só não sai e-mail. */
const PEDIDOS_POR_CLIENTE_POR_HORA = 3;
const PEDIDOS_POR_IP_POR_HORA = 10;

const RESPOSTA_NEUTRA = "Se houver um cadastro correspondente, enviaremos um link para redefinir a senha.";

function isValidEmail(value: string) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}

function ipDoPedido(request: Request) {
  return (
    String(request.headers.get("x-forwarded-for") || "").split(",")[0].trim() ||
    String(request.headers.get("x-real-ip") || "").trim() ||
    null
  );
}

/* O endereço da loja que o cliente está usando (domínio próprio ou o da
   Ktalogu). Atrás do proxy o protocolo pode chegar como http: fora do
   computador local, é sempre https. */
function origemDaLoja(request: Request) {
  const origem = resolvePublicOrigin(request);
  return /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(origem) || /\.localhost(:\d+)?$/i.test(origem)
    ? origem
    : origem.replace(/^http:\/\//i, "https://");
}

export async function POST(request: Request) {
  try {
    const body = (await request.json().catch(() => null)) as
      | {
          slug?: unknown;
          email?: unknown;
        }
      | null;

    const slug = typeof body?.slug === "string" ? body.slug.trim() : "";
    const email = typeof body?.email === "string" ? body.email.trim().toLowerCase() : "";

    if (!slug || !email || !isValidEmail(email)) {
      return NextResponse.json({ error: "Informe um e-mail valido." }, { status: 400 });
    }

    const admin = createAdminClient();
    const { data: profile } = await admin
      .from("profiles")
      .select("id,store_name,catalog_name,catalog_logo_url,logo_url,primary_color,company_email")
      .eq("slug", slug)
      .maybeSingle();

    if (!profile?.id) {
      return NextResponse.json({ error: "Loja nao encontrada." }, { status: 404 });
    }

    /*
      Sem o e-mail da loja configurado no servidor, nao ha como mandar o link.

      O caminho antigo pedia o "esqueci a senha" ao Supabase, que manda o
      e-mail de SISTEMA da Ktalogu e leva ao login do painel: para quem tambem
      tem conta na Ktalogu, o link trocava a senha do painel, nao a da loja, e
      quem so tem cadastro na loja nao recebia nada. Ele saiu. A resposta vem
      antes de procurar o cliente e e igual para qualquer e-mail, para nao
      revelar quem tem cadastro.
    */
    if (!emailDaLojaConfigurado()) {
      console.error("Esqueci minha senha do portal sem e-mail configurado: falta RESEND_API_KEY / EMAIL_REMETENTE no apps/public.");
      return NextResponse.json(
        { error: "A loja ainda não consegue enviar o link por e-mail. Para criar uma nova senha, fale com a loja." },
        { status: 503 }
      );
    }

    const { data: client } = await admin
      .from("clients")
      .select("id, name, email, portal_enabled")
      .eq("user_id", profile.id)
      /* `_` e `%` no e-mail seriam curingas na comparação: escapados, ele bate
         só com ele mesmo. */
      .ilike("email", email.replace(/[\\%_]/g, "\\$&"))
      .maybeSingle();

    /* Portal desligado pela loja continua desligado. Antes, pedir "esqueci minha
       senha" reativava o acesso sozinho, o que anulava a decisao de quem
       desligou. A resposta segue neutra para nao revelar se o e-mail existe. */
    if (client?.id && client.portal_enabled === false) {
      return NextResponse.json({
        ok: true,
        message: "Se o e-mail estiver cadastrado, você receberá as instruções.",
      });
    }

    if (!client?.id) {
      return NextResponse.json({ ok: true, message: RESPOSTA_NEUTRA });
    }

    /*
      O link sai daqui, com o nome da loja.

      Antes o pedido ia para o Supabase, que só manda e-mail para quem existe no
      cadastro de login dele — ou seja, só para quem já tinha entrado com Google.
      Quem se cadastrou com senha nunca recebia nada. Agora o sistema gera um
      código de uso único, guarda só o resumo dele e manda o link pelo e-mail
      da loja.
    */
    const umaHoraAtras = new Date(Date.now() - 60 * 60 * 1000).toISOString();
    const ip = ipDoPedido(request);

    const { count: doCliente } = await admin
      .from("client_portal_codes")
      .select("id", { count: "exact", head: true })
      .eq("client_id", client.id)
      .eq("tipo", "redefinir_senha")
      .gte("criado_em", umaHoraAtras);
    if ((doCliente ?? 0) >= PEDIDOS_POR_CLIENTE_POR_HORA) {
      return NextResponse.json({ ok: true, message: RESPOSTA_NEUTRA });
    }

    if (ip) {
      const { count: doIp } = await admin
        .from("client_portal_codes")
        .select("id", { count: "exact", head: true })
        .eq("ip", ip)
        .gte("criado_em", umaHoraAtras);
      if ((doIp ?? 0) >= PEDIDOS_POR_IP_POR_HORA) {
        return NextResponse.json({ ok: true, message: RESPOSTA_NEUTRA });
      }
    }

    const codigo = randomBytes(32).toString("base64url");
    const { error: erroDoCodigo } = await admin.from("client_portal_codes").insert({
      store_id: profile.id,
      client_id: client.id,
      tipo: "redefinir_senha",
      codigo_hash: createHash("sha256").update(codigo).digest("hex"),
      expira_em: new Date(Date.now() + VALIDADE_DO_LINK_MS).toISOString(),
      ip,
    });
    if (erroDoCodigo) {
      return NextResponse.json(
        { error: "Nao foi possivel enviar o link agora. Tente novamente em instantes." },
        { status: 503 }
      );
    }

    const nomeDaLoja = String(profile.catalog_name || profile.store_name || "Loja").trim();
    const link = new URL(`/${slug}/cliente/redefinir-senha`, origemDaLoja(request));
    link.searchParams.set("codigo", codigo);
    const primeiroNome = String(client.name || "").trim().split(/\s+/)[0] || "";
    const conteudo = montarEmailDaLoja({
      loja: { nome: nomeDaLoja, logo: profile.catalog_logo_url || profile.logo_url, cor: profile.primary_color },
      resumo: `Crie uma nova senha para entrar na ${nomeDaLoja}.`,
      titulo: "Redefinir sua senha",
      paragrafos: [
        primeiroNome ? `Olá, ${primeiroNome}.` : "Olá.",
        `Recebemos um pedido para criar uma nova senha da sua conta na ${nomeDaLoja}. O link abaixo vale por 1 hora e funciona uma vez só.`,
      ],
      botao: { texto: "Criar nova senha", link: link.toString() },
      observacao: "Se não foi você que pediu, é só ignorar este e-mail: sua senha continua a mesma.",
    });
    const envio = await enviarEmailDaLoja({
      para: String(client.email || email),
      assunto: `Redefinir sua senha na ${nomeDaLoja}`,
      html: conteudo.html,
      texto: conteudo.texto,
      nomeDaLoja,
      responderPara: profile.company_email,
    });
    if (!envio.ok) {
      console.error("Falha ao enviar o e-mail de nova senha do portal:", envio.erro);
      return NextResponse.json(
        { error: "Nao foi possivel enviar o link agora. Solicite um novo acesso diretamente com a loja." },
        { status: 503 }
      );
    }

    return NextResponse.json({ ok: true, message: RESPOSTA_NEUTRA });
  } catch (error) {
    console.error("Erro ao solicitar redefinicao do portal:", error);
    return NextResponse.json(
      { error: "Nao foi possivel enviar o link agora. Tente novamente em instantes." },
      { status: 500 }
    );
  }
}
