import { createHash, randomBytes } from "node:crypto";
import { NextResponse } from "next/server";
import { canCompany, getCompanyContext } from "@/lib/company-context";
import { createAdminClient, createClient } from "@/lib/supabase-server";

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

function readAdminDerivedPublicOrigin(request: Request) {
  const envBase = String(process.env.NEXT_PUBLIC_PUBLIC_CATALOG_BASE_URL || process.env.PUBLIC_CATALOG_BASE_URL || "").trim();
  if (envBase) return envBase.replace(/\/$/, "");

  const requestUrl = new URL(request.url);
  const forwardedHost = String(request.headers.get("x-forwarded-host") || "")
    .split(",")[0]
    .trim();
  const forwardedProto = String(request.headers.get("x-forwarded-proto") || "")
    .split(",")[0]
    .trim()
    .replace(/:$/, "");
  const host = forwardedHost || request.headers.get("host") || requestUrl.host;
  const protocol = forwardedProto || requestUrl.protocol.replace(/:$/, "") || "http";

  return `${protocol}://${host}`
    .replace(":3002", ":3001")
    .replace(/\/\/admin\./, "//")
    .replace(/\/$/, "");
}

function sha256(value: string) {
  return createHash("sha256").update(value).digest("hex");
}

/*
  Liga e desliga o acesso do cliente ao portal.

  A ficha do cliente mostrava "Portal ativo" ou "Portal desativado" como um selo
  informativo, e nao havia como mudar: o campo existia no banco e ninguem
  conseguia mexer nele pelo sistema. Aqui ele vira uma chave de verdade, e a
  sessao aberta tambem cai, porque desligar o acesso e para valer agora, nao
  quando a sessao expirar.
*/
export async function PATCH(request: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (!user) {
    return NextResponse.json({ error: "Nao autenticado." }, { status: 401 });
  }

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "clients.list.write")) {
    return NextResponse.json({ error: "Sem permissao." }, { status: 403 });
  }

  const body = (await request.json().catch(() => null)) as { clientId?: unknown; enabled?: unknown } | null;
  const clientId = typeof body?.clientId === "string" ? body.clientId.trim() : "";
  const enabled = body?.enabled === true;

  if (!clientId) {
    return NextResponse.json({ error: "Cliente invalido." }, { status: 400 });
  }

  const admin = createAdminClient();
  const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [ctx.ownerId ?? user.id];

  const { data: updated, error } = await admin
    .from("clients")
    .update({ portal_enabled: enabled, updated_at: new Date().toISOString() })
    .eq("id", clientId)
    .in("user_id", tenantIds)
    .select("id,portal_enabled")
    .maybeSingle();

  if (error) return NextResponse.json({ error: error.message }, { status: 400 });
  if (!updated?.id) return NextResponse.json({ error: "Cliente nao encontrado." }, { status: 404 });

  if (!enabled) {
    await admin
      .from("client_portal_sessions")
      .update({ revoked_at: new Date().toISOString() })
      .eq("client_id", clientId)
      .is("revoked_at", null);
  }

  return NextResponse.json({ ok: true, portal_enabled: updated.portal_enabled });
}

export async function POST(request: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (!user) {
    return NextResponse.json({ error: "Nao autenticado." }, { status: 401 });
  }

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "clients.list.write")) {
    return NextResponse.json({ error: "Sem permissao." }, { status: 403 });
  }

  try {
    const body = (await request.json().catch(() => null)) as { clientId?: unknown } | null;
    const clientId = typeof body?.clientId === "string" ? body.clientId.trim() : "";

    if (!clientId) {
      return NextResponse.json({ error: "Cliente invalido." }, { status: 400 });
    }

    const admin = createAdminClient();
    const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [ctx.ownerId ?? user.id];
    const [{ data: client }, { data: profilesData }, { data: domainsData }] = await Promise.all([
      admin
        .from("clients")
        .select("id,name,email,user_id,portal_enabled")
        .eq("id", clientId)
        .in("user_id", tenantIds)
        .maybeSingle(),
      admin.from("profiles").select("id,slug").in("id", tenantIds),
      admin.from("profile_custom_domains").select("profile_id,domain,verified").in("profile_id", tenantIds),
    ]);

    if (!client?.id) {
      return NextResponse.json({ error: "Cliente nao encontrado." }, { status: 404 });
    }

    const email = String(client.email || "").trim().toLowerCase();
    if (!email) {
      return NextResponse.json({ error: "Este cliente nao possui e-mail cadastrado." }, { status: 400 });
    }

    const profileWithSlug = (profilesData || []).find((item) => Boolean((item as { slug?: string | null }).slug)) as
      | { id?: string | null; slug?: string | null }
      | undefined;
    const slug = String(profileWithSlug?.slug || "").trim();

    if (!slug) {
      return NextResponse.json({ error: "Nao foi possivel identificar o slug da loja." }, { status: 400 });
    }

    const verifiedDomain = (domainsData || []).find((item) => Boolean((item as { verified?: boolean | null }).verified)) as
      | { domain?: string | null; verified?: boolean | null }
      | undefined;

    const publicOrigin = verifiedDomain?.domain
      ? `https://${String(verifiedDomain.domain).trim().replace(/^https?:\/\//, "").replace(/\/$/, "")}`
      : readAdminDerivedPublicOrigin(request);

    const token = randomBytes(32).toString("hex");
    const tokenHash = sha256(token);
    const expiresAt = new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString();
    const forwardedFor = String(request.headers.get("x-forwarded-for") || "")
      .split(",")[0]
      .trim();
    const userAgent = String(request.headers.get("user-agent") || "").trim().slice(0, 500) || "admin-portal-access";

    await admin
      .from("clients")
      .update({
        portal_enabled: true,
        updated_at: new Date().toISOString(),
      })
      .eq("id", client.id);

    await admin
      .from("client_portal_sessions")
      .update({ revoked_at: new Date().toISOString() })
      .eq("client_id", client.id)
      .is("revoked_at", null)
      .eq("user_agent", "admin-portal-access");

    const { error: sessionError } = await admin.from("client_portal_sessions").insert({
      user_id: client.user_id,
      client_id: client.id,
      token_hash: tokenHash,
      ip_address: forwardedFor || null,
      user_agent: "admin-portal-access",
      expires_at: expiresAt,
      last_seen_at: new Date().toISOString(),
    });

    if (sessionError) {
      throw sessionError;
    }

    const accessUrl = new URL(`/${slug}/cliente/redefinir-senha`, publicOrigin);
    accessUrl.searchParams.set("portal_token", token);
    accessUrl.searchParams.set("email", email);

    return NextResponse.json({
      ok: true,
      email,
      slug,
      access_url: accessUrl.toString(),
      expires_at: expiresAt,
      message: "Link seguro de acesso ao portal gerado com sucesso.",
    });
  } catch (error) {
    console.error("Erro ao enviar acesso ao portal:", error);
    return NextResponse.json(
      { error: "Nao foi possivel gerar o acesso seguro do portal agora. Tente novamente em instantes." },
      { status: 500 }
    );
  }
}
