import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { buildPublicUrl } from "@/lib/request-origin";
import { createAdminClient } from "@/lib/supabase-admin";
import { COOKIE_DO_VINCULO } from "@/lib/passagem-do-login";

/*
  Grava o cookie da sessao do portal depois do login (o token chega pela URL
  no meio do redirecionamento e vira cookie aqui).

  Duas travas que faltavam: o token so vira cookie se for uma sessao valida
  desta loja (antes qualquer texto virava cookie), e o destino so pode ser um
  caminho da propria loja (antes "//outro-site" levava para fora).

  Tambem recebe a PASSAGEM do login com o Google em loja com dominio proprio
  (migration 163): o endereco principal manda o cliente para ca com um codigo
  de uso unico, e a sessao nasce aqui, no dominio da loja, onde o carrinho
  esta. So vale no navegador que comecou o login (cookie do vinculo).
*/

const COOKIE = "ks_client_portal";

/* O endereco publico com o protocolo certo. Atras da Cloudflare o
   x-forwarded-proto chega "http" (ou o proprio Next o preenche assim), e um
   redirecionamento para http num dominio que so existe em https chegava sem
   o cookie seguro: a pessoa caia no login de novo. Dominio de verdade e
   https; so o endereco de desenvolvimento (localhost, IP, porta a mostra)
   fica como veio. */
function destinoNaLoja(request: Request, caminho: string) {
  const url = buildPublicUrl(request, caminho);
  const desenvolvimento =
    /^(localhost|127\.0\.0\.1)$|\.localhost$/i.test(url.hostname) || /^\d{1,3}(\.\d{1,3}){3}$/.test(url.hostname) || Boolean(url.port);
  if (url.protocol === "http:" && !desenvolvimento) url.protocol = "https:";
  return url;
}

function caminhoSeguro(valor: string | null | undefined, slug?: string | null) {
  const next = String(valor || "").trim();
  if (!next.startsWith("/") || next.startsWith("//") || next.startsWith("/\\") || /[\r\n]/.test(next)) return null;
  if (slug && !next.startsWith(`/${slug}`)) return null;
  return next;
}

function slugDoCaminho(caminho: string | null) {
  const partes = String(caminho || "").split("/").filter(Boolean);
  return partes[0] ? partes[0].toLowerCase() : "";
}

async function sessaoValida(slug: string, token: string) {
  if (!slug || !token || token.length > 200) return false;
  try {
    const admin = createAdminClient();
    const { data } = await admin.rpc("client_portal_get_session", { p_slug: slug, p_session_token: token });
    return Boolean((data as { client?: { id?: string } } | null)?.client?.id);
  } catch {
    return false;
  }
}

function respostaComCookie(token: string, destino: URL) {
  const response = NextResponse.redirect(destino, { status: 303 });
  response.cookies.set({
    name: COOKIE,
    value: token,
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    sameSite: "lax",
    path: "/",
    maxAge: 60 * 60 * 24 * 15,
  });
  return response;
}

async function trocarPassagem(request: Request, codigo: string, nextBruto: string | null) {
  const next = caminhoSeguro(nextBruto);
  const slug = slugDoCaminho(next);
  if (!next || !slug) {
    return NextResponse.redirect(destinoNaLoja(request, "/"), { status: 303 });
  }

  const vinculo = (await cookies()).get(COOKIE_DO_VINCULO)?.value || "";
  const ip = String(request.headers.get("x-forwarded-for") || "").split(",")[0]?.trim() || "";
  let token = "";
  try {
    const admin = createAdminClient();
    const { data } = await admin.rpc("client_portal_trocar_passagem", {
      p_slug: slug,
      p_codigo: codigo,
      p_vinculo: vinculo,
      p_ip: ip,
      p_user_agent: request.headers.get("user-agent") || "",
    });
    const resultado = data as { ok?: boolean; session_token?: string } | null;
    if (resultado?.ok && resultado.session_token) token = String(resultado.session_token);
  } catch {
    token = "";
  }

  /* Passagem vencida, ja usada ou de outro navegador: volta para entrar de
     novo, com o recado, sem perder o caminho de onde a pessoa vinha. */
  if (!token) {
    const login = destinoNaLoja(request, `/${slug}/cliente/login`);
    if (next !== `/${slug}/cliente`) login.searchParams.set("next", next);
    login.searchParams.set("error", "Não deu para concluir o login com o Google. Tente de novo.");
    const resposta = NextResponse.redirect(login, { status: 303 });
    resposta.cookies.delete(COOKIE_DO_VINCULO);
    return resposta;
  }

  const resposta = respostaComCookie(token, destinoNaLoja(request, next));
  resposta.cookies.delete(COOKIE_DO_VINCULO);
  return resposta;
}

export async function GET(request: Request) {
  try {
    const url = new URL(request.url);
    const passagem = String(url.searchParams.get("passagem") || "").trim();
    if (passagem) return await trocarPassagem(request, passagem, url.searchParams.get("next"));

    const token = String(url.searchParams.get("token") || "").trim();
    const next = caminhoSeguro(url.searchParams.get("next"));
    const slug = slugDoCaminho(next);

    if (!token || !next || !slug) {
      return NextResponse.redirect(destinoNaLoja(request, "/"), { status: 303 });
    }
    if (!(await sessaoValida(slug, token))) {
      return NextResponse.redirect(destinoNaLoja(request, `/${slug}/cliente/login`), { status: 303 });
    }
    return respostaComCookie(token, destinoNaLoja(request, next));
  } catch {
    return NextResponse.redirect(destinoNaLoja(request, "/"), { status: 303 });
  }
}

export async function POST(request: Request) {
  try {
    const body = (await request.json()) as { slug?: string; token?: string };
    const slug = String(body?.slug || "").trim().toLowerCase();
    const token = String(body?.token || "").trim();

    if (!slug || !token || !/^[a-z0-9-]+$/.test(slug)) {
      return NextResponse.json({ error: "Sessão inválida." }, { status: 400 });
    }
    if (!(await sessaoValida(slug, token))) {
      return NextResponse.json({ error: "Sessão inválida." }, { status: 401 });
    }
    return respostaComCookie(token, destinoNaLoja(request, `/${slug}/cliente`));
  } catch (err) {
    const message =
      typeof err === "object" && err && "message" in err && typeof err.message === "string"
        ? err.message
        : "Não foi possível estabilizar a sessão.";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
