import { NextResponse } from "next/server";
import { createClient } from "@/lib/supabase-server";
import { createAdminClient } from "@/lib/supabase-admin";
import { isOwnerUser } from "@/lib/owner-auth";

/**
 * O cadastro dos popups do sistema.
 *
 * Mesma divisão de trabalho das tarjas: a rota confere a sessão do dono e faz
 * tudo com a chave de serviço. As tabelas têm RLS ligado e nenhuma política,
 * então do navegador ninguém alcança nem para ler.
 */

const CAMPOS =
  "id,title,message,image_url,image_url_mobile,image_side,background_color,text_color,cta_label,cta_url,cta_new_tab,require_ack,ack_label,frequency,audience,active,start_at,end_at,created_at,updated_at";

function texto(valor: unknown) {
  return typeof valor === "string" ? valor.trim() : "";
}

function booleano(valor: unknown, padrao: boolean) {
  return typeof valor === "boolean" ? valor : padrao;
}

function dataIso(valor: unknown) {
  const bruto = texto(valor);
  if (!bruto) return null;
  const data = new Date(bruto);
  return Number.isNaN(data.getTime()) ? null : data.toISOString();
}

/**
 * Cor em hexadecimal, ou o padrão.
 *
 * Vale a pena conferir aqui: a cor entra num `style` do lado do navegador, e
 * texto solto nesse lugar é onde nasce injeção de CSS. Só passam três ou seis
 * dígitos depois do `#`.
 */
function cor(valor: unknown, padrao: string) {
  const bruto = texto(valor);
  return /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(bruto) ? bruto : padrao;
}

/** Endereço de imagem ou de botão: só http(s), e nada de `javascript:`. */
function endereco(valor: unknown) {
  const bruto = texto(valor);
  if (!bruto) return null;
  try {
    const url = new URL(bruto);
    return url.protocol === "http:" || url.protocol === "https:" ? bruto : null;
  } catch {
    return null;
  }
}

function ladoDaImagem(valor: unknown) {
  return texto(valor).toLowerCase() === "right" ? "right" : "left";
}

function frequencia(valor: unknown) {
  const limpo = texto(valor).toLowerCase();
  return limpo === "daily" || limpo === "always" ? limpo : "once";
}

function publico(valor: unknown) {
  return texto(valor).toLowerCase() === "selected" ? "selected" : "all";
}

function listaDeEmpresas(valor: unknown) {
  if (!Array.isArray(valor)) return [];
  const ids = valor.map((item) => texto(item)).filter(Boolean);
  return [...new Set(ids)];
}

async function conferirDono() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();

  if (!user || !isOwnerUser({ id: user.id, email: user.email })) {
    return { ok: false as const, status: 403 };
  }
  return { ok: true as const, status: 200 };
}

/** Reescreve a lista de empresas do popup. Só faz sentido com público "selected". */
async function gravarEmpresas(
  admin: ReturnType<typeof createAdminClient>,
  popupId: string,
  alvo: "all" | "selected",
  empresas: string[]
) {
  await admin.from("system_popup_companies").delete().eq("popup_id", popupId);
  if (alvo !== "selected" || empresas.length === 0) return;
  await admin.from("system_popup_companies").insert(empresas.map((company_id) => ({ popup_id: popupId, company_id })));
}

export async function GET() {
  const auth = await conferirDono();
  if (!auth.ok) return NextResponse.json({ error: "Sem permissão." }, { status: auth.status });

  const admin = createAdminClient();
  const { data, error } = await admin.from("system_popups").select(CAMPOS).order("created_at", { ascending: false });
  if (error) return NextResponse.json({ error: "Não foi possível carregar os popups." }, { status: 400 });

  const popups = Array.isArray(data) ? data : [];
  const ids = popups.map((linha) => String(linha.id));

  /* As empresas de todos os popups numa consulta só: uma por popup faria a
     lista abrir devagar quando houvesse muitos. */
  const porPopup = new Map<string, string[]>();
  if (ids.length > 0) {
    const { data: vinculos } = await admin.from("system_popup_companies").select("popup_id,company_id").in("popup_id", ids);
    for (const vinculo of vinculos ?? []) {
      const chave = String(vinculo.popup_id);
      porPopup.set(chave, [...(porPopup.get(chave) ?? []), String(vinculo.company_id)]);
    }
  }

  return NextResponse.json({
    ok: true,
    popups: popups.map((linha) => ({ ...linha, company_ids: porPopup.get(String(linha.id)) ?? [] })),
  });
}

export async function POST(request: Request) {
  const auth = await conferirDono();
  if (!auth.ok) return NextResponse.json({ error: "Sem permissão." }, { status: auth.status });

  const body = (await request.json().catch(() => null)) as Record<string, unknown> | null;
  const title = texto(body?.title);
  if (!title) return NextResponse.json({ error: "Informe o título do popup." }, { status: 400 });

  const alvo = publico(body?.audience);
  const empresas = listaDeEmpresas(body?.company_ids);
  if (alvo === "selected" && empresas.length === 0) {
    return NextResponse.json({ error: "Escolha pelo menos uma empresa." }, { status: 400 });
  }

  const admin = createAdminClient();
  const { data, error } = await admin
    .from("system_popups")
    .insert({
      title,
      message: texto(body?.message) || null,
      image_url: endereco(body?.image_url),
      image_url_mobile: endereco(body?.image_url_mobile),
      image_side: ladoDaImagem(body?.image_side),
      background_color: cor(body?.background_color, "#4F46E5"),
      text_color: cor(body?.text_color, "#FFFFFF"),
      cta_label: texto(body?.cta_label) || null,
      cta_url: endereco(body?.cta_url),
      cta_new_tab: booleano(body?.cta_new_tab, true),
      require_ack: booleano(body?.require_ack, false),
      ack_label: texto(body?.ack_label) || null,
      frequency: frequencia(body?.frequency),
      audience: alvo,
      active: booleano(body?.active, true),
      start_at: dataIso(body?.start_at),
      end_at: dataIso(body?.end_at),
    })
    .select("id")
    .single();

  if (error || !data?.id) return NextResponse.json({ error: "Não foi possível salvar o popup." }, { status: 400 });

  await gravarEmpresas(admin, String(data.id), alvo, empresas);
  return NextResponse.json({ ok: true, id: data.id });
}

export async function PATCH(request: Request) {
  const auth = await conferirDono();
  if (!auth.ok) return NextResponse.json({ error: "Sem permissão." }, { status: auth.status });

  const body = (await request.json().catch(() => null)) as Record<string, unknown> | null;
  const id = texto(body?.id);
  if (!id) return NextResponse.json({ error: "Popup inválido." }, { status: 400 });

  const admin = createAdminClient();
  const { data: atual } = await admin.from("system_popups").select("audience").eq("id", id).maybeSingle();
  if (!atual) return NextResponse.json({ error: "Popup não encontrado." }, { status: 404 });

  /* Só mexe no que veio. Salvar a lista da tela inteira em cada edição faria
     um campo esquecido apagar o que estava gravado. */
  const payload: Record<string, unknown> = {};
  if (body?.title !== undefined) {
    const title = texto(body.title);
    if (!title) return NextResponse.json({ error: "Informe o título do popup." }, { status: 400 });
    payload.title = title;
  }
  if (body?.message !== undefined) payload.message = texto(body.message) || null;
  if (body?.image_url !== undefined) payload.image_url = endereco(body.image_url);
  if (body?.image_url_mobile !== undefined) payload.image_url_mobile = endereco(body.image_url_mobile);
  if (body?.image_side !== undefined) payload.image_side = ladoDaImagem(body.image_side);
  if (body?.background_color !== undefined) payload.background_color = cor(body.background_color, "#4F46E5");
  if (body?.text_color !== undefined) payload.text_color = cor(body.text_color, "#FFFFFF");
  if (body?.cta_label !== undefined) payload.cta_label = texto(body.cta_label) || null;
  if (body?.cta_url !== undefined) payload.cta_url = endereco(body.cta_url);
  if (body?.cta_new_tab !== undefined) payload.cta_new_tab = booleano(body.cta_new_tab, true);
  if (body?.require_ack !== undefined) payload.require_ack = booleano(body.require_ack, false);
  if (body?.ack_label !== undefined) payload.ack_label = texto(body.ack_label) || null;
  if (body?.frequency !== undefined) payload.frequency = frequencia(body.frequency);
  if (body?.active !== undefined) payload.active = booleano(body.active, true);
  if (body?.start_at !== undefined) payload.start_at = dataIso(body.start_at);
  if (body?.end_at !== undefined) payload.end_at = dataIso(body.end_at);

  const alvo = body?.audience !== undefined ? publico(body.audience) : (String(atual.audience) as "all" | "selected");
  if (body?.audience !== undefined) payload.audience = alvo;

  const mexeuNasEmpresas = body?.company_ids !== undefined || body?.audience !== undefined;
  const empresas = listaDeEmpresas(body?.company_ids);
  if (mexeuNasEmpresas && alvo === "selected" && empresas.length === 0) {
    return NextResponse.json({ error: "Escolha pelo menos uma empresa." }, { status: 400 });
  }

  /* `updated_at` sai daqui de propósito: o gatilho do banco carimba sozinho, e
     é ele que faz o popup "uma vez por pessoa" voltar a aparecer depois de uma
     correção de texto. */
  const { error } = await admin.from("system_popups").update(payload).eq("id", id);
  if (error) return NextResponse.json({ error: "Não foi possível atualizar o popup." }, { status: 400 });

  if (mexeuNasEmpresas) await gravarEmpresas(admin, id, alvo, empresas);
  return NextResponse.json({ ok: true });
}

export async function DELETE(request: Request) {
  const auth = await conferirDono();
  if (!auth.ok) return NextResponse.json({ error: "Sem permissão." }, { status: auth.status });

  const { searchParams } = new URL(request.url);
  const id = texto(searchParams.get("id"));
  if (!id) return NextResponse.json({ error: "Popup inválido." }, { status: 400 });

  /* Os vínculos e as visualizações somem junto, pela chave estrangeira. */
  const admin = createAdminClient();
  const { error } = await admin.from("system_popups").delete().eq("id", id);
  if (error) return NextResponse.json({ error: "Não foi possível excluir o popup." }, { status: 400 });
  return NextResponse.json({ ok: true });
}
