import { NextResponse } from "next/server";
import { createClient, createAdminClient } from "@/lib/supabase-server";
import { canCompany, canReadModuleLookup, getCompanyContext } from "@/lib/company-context";

/**
 * Os custos que variam com a venda: imposto, taxa de recebimento, perda.
 *
 * O GET devolve, junto com a configuração, o faturamento mês a mês e a alíquota
 * que o regime produz hoje — a tela precisa dos três para explicar o número em
 * vez de só exibi-lo. Alíquota de imposto sem mostrar de onde veio é um número
 * que ninguém confere e todo mundo desconfia.
 */

const REGIMES = ["simples_nacional", "lucro_presumido", "lucro_real", "mei", "isento"] as const;
const ANEXOS = ["I", "II", "III", "IV", "V"] as const;

const PERCENTUAIS = [
  "fee_pix_percent",
  "fee_debit_percent",
  "fee_credit_percent",
  "fee_boleto_percent",
  "fee_transfer_percent",
  "fee_cash_percent",
  "loss_percent",
  "other_variable_percent",
] as const;

function percentual(valor: unknown): number | null {
  if (valor === null || valor === undefined || valor === "") return null;
  const n = Number(valor);
  if (!Number.isFinite(n)) return null;
  /* O banco recusa fora de 0–100; recusar aqui devolve mensagem em vez de
     erro de constraint. */
  if (n < 0 || n > 100) return null;
  return Math.round(n * 1000) / 1000;
}

export async function GET() {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const ctx = await getCompanyContext(supabase, user);
  /* Esta configuração é apoio de duas frentes: a tela de Impostos e taxas,
     em Precificação, e as contas do Financeiro. Quem lê qualquer tela de
     um dos dois lê daqui — senão a tela de impostos abria vazia para quem
     recebeu só ela. */
  if (!canReadModuleLookup(ctx, user.id, "pricing") && !canReadModuleLookup(ctx, user.id, "financial")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const admin = createAdminClient();

  const [config, faturamento, aliquota] = await Promise.all([
    admin.from("company_pricing_settings").select("*").eq("company_id", ctx.companyId).maybeSingle(),
    admin
      .from("company_revenue_history")
      .select("competencia,amount,source")
      .eq("company_id", ctx.companyId)
      .order("competencia", { ascending: false })
      .limit(24),
    admin.rpc("aliquota_de_imposto_da_empresa", { p_company_id: ctx.companyId }),
  ]);

  return NextResponse.json({
    ok: true,
    settings: config.data ?? null,
    revenue: faturamento.data ?? [],
    aliquota_atual: Number(aliquota.data ?? 0),
  });
}

export async function PUT(req: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "pricing.taxes.write")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

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

  const regime = String(body.tax_regime ?? "");
  if (!REGIMES.includes(regime as (typeof REGIMES)[number])) {
    return NextResponse.json({ error: "Regime tributário inválido." }, { status: 400 });
  }

  const anexo = body.simples_annex ? String(body.simples_annex) : null;
  if (regime === "simples_nacional" && !ANEXOS.includes(anexo as (typeof ANEXOS)[number])) {
    return NextResponse.json({ error: "Escolha o anexo do Simples Nacional." }, { status: 400 });
  }

  const patch: Record<string, unknown> = {
    company_id: ctx.companyId,
    tax_regime: regime,
    /* Anexo só faz sentido no Simples: guardá-lo em outro regime deixaria um
       valor que a tela mostra e o cálculo ignora. */
    simples_annex: regime === "simples_nacional" ? anexo : null,
    manual_tax_percent:
      regime === "lucro_presumido" || regime === "lucro_real"
        ? percentual(body.manual_tax_percent) ?? 0
        : null,
    mei_monthly_amount: regime === "mei" ? Number(body.mei_monthly_amount ?? 0) || 0 : null,
    updated_at: new Date().toISOString(),
  };

  for (const campo of PERCENTUAIS) {
    const valor = percentual(body[campo]);
    if (valor === null && body[campo] !== undefined && body[campo] !== "") {
      return NextResponse.json(
        { error: `O campo ${campo} precisa ser um percentual entre 0 e 100.` },
        { status: 400 }
      );
    }
    patch[campo] = valor ?? 0;
  }

  const admin = createAdminClient();
  const { error } = await admin
    .from("company_pricing_settings")
    .upsert(patch, { onConflict: "company_id" });

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

  /* Depois de salvar, o faturamento é reconstruído do histórico de vendas.
     Meses corrigidos à mão são preservados pela própria função. */
  await admin.rpc("preencher_faturamento_do_historico", {
    p_company_id: ctx.companyId,
    p_meses: 24,
  });

  const { data: aliquota } = await admin.rpc("aliquota_de_imposto_da_empresa", {
    p_company_id: ctx.companyId,
  });

  return NextResponse.json({ ok: true, aliquota_atual: Number(aliquota ?? 0) });
}

/** Correção manual de um mês de faturamento. */
export async function PATCH(req: Request) {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: "Não autenticado." }, { status: 401 });

  const ctx = await getCompanyContext(supabase, user);
  if (!canCompany(ctx, user.id, "pricing.taxes.write")) {
    return NextResponse.json({ error: "Sem permissão." }, { status: 403 });
  }

  const body = (await req.json().catch(() => null)) as
    | { competencia?: unknown; amount?: unknown }
    | null;

  const competencia = typeof body?.competencia === "string" ? body.competencia : "";
  if (!/^\d{4}-\d{2}-01$/.test(competencia)) {
    return NextResponse.json({ error: "Competência inválida." }, { status: 400 });
  }

  const amount = Number(body?.amount);
  if (!Number.isFinite(amount) || amount < 0) {
    return NextResponse.json({ error: "Valor inválido." }, { status: 400 });
  }

  const admin = createAdminClient();
  const { error } = await admin.from("company_revenue_history").upsert(
    {
      company_id: ctx.companyId,
      competencia,
      amount: Math.round(amount * 100) / 100,
      /* Marcar como informado é o que impede a próxima sincronização de
         sobrescrever: quem corrigiu sabe algo que o sistema não sabe. */
      source: "informado",
      updated_at: new Date().toISOString(),
    },
    { onConflict: "company_id,competencia" }
  );

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

  const { data: aliquota } = await admin.rpc("aliquota_de_imposto_da_empresa", {
    p_company_id: ctx.companyId,
  });

  return NextResponse.json({ ok: true, aliquota_atual: Number(aliquota ?? 0) });
}
