import type { SupabaseClient, User } from "@supabase/supabase-js";
import { NextResponse } from "next/server";

import { canCompany, getCompanyContext, type CompanyContext, type CompanyPermission } from "@/lib/company-context";
import { assinaturaDaEmpresa } from "@/lib/fiscal/servidor/assinatura-da-empresa";
import { createAdminClient, createClient } from "@/lib/supabase-server";

import { digitaisLiberadosAgora } from "../liberacao-do-banco";

/**
 * O que toda rota da área "Produtos digitais" faz antes de qualquer coisa:
 * quem é, de que empresa, se a área já está liberada para ela, se a pessoa
 * pode, e se a assinatura da EMPRESA está em dia.
 *
 * As tabelas dos digitais não têm política para o navegador: quem lê e grava
 * é a chave de serviço, DEPOIS desta conferência, sempre filtrando por
 * `lojaId` — o dono da loja, o mesmo `user_id` dos produtos e pedidos.
 */

export type ContextoDigital = {
  admin: SupabaseClient;
  user: User;
  ctx: CompanyContext;
  lojaId: string;
  pode: (permissao: CompanyPermission) => boolean;
  /* A assinatura da empresa: "teste" tem espaço menor (lib/digitais/limites.ts). */
  situacao: string;
  /* A área de Produtos digitais está liberada (DIGITAIS_LIBERADOS ou a tabela digitais_ajustes). Sem ela,
     só o vídeo do produto passa (OpcoesDoContexto.videoDoProduto). */
  liberado: boolean;
};

export type OpcoesDoContexto = {
  /*
   * O vídeo da galeria do produto (migration 183) é de TODAS as empresas
   * (decisão do Natan, 13/10/2026), mesmo sem Produtos digitais: ele usa os
   * mesmos arquivos e o mesmo espaço. Nas rotas marcadas assim, quem não tem
   * a área liberada passa com a permissão de editar produto e `liberado: false`
   * (a rota então só aceita vídeo de produto).
   */
  videoDoProduto?: boolean;
};

const PERMISSOES_DO_PRODUTO: CompanyPermission[] = ["catalog.products.write", "products.catalog.write"];

export class ErroDigital extends Error {
  readonly status: number;
  readonly extra?: Record<string, unknown>;
  constructor(mensagem: string, status = 400, extra?: Record<string, unknown>) {
    super(mensagem);
    this.status = status;
    this.extra = extra;
  }
}

export function erroDigital(mensagem: string, status: number, extra?: Record<string, unknown>) {
  return NextResponse.json({ error: mensagem, ...(extra ?? {}) }, { status, headers: { "cache-control": "no-store" } });
}

const MENSAGEM_DA_ASSINATURA: Record<string, string> = {
  expirada: "A assinatura do Ktalogu desta empresa venceu. Renove em Assinatura para voltar a usar os produtos digitais.",
};

export async function abrirContextoDigital(
  permissao: CompanyPermission | CompanyPermission[],
  opcoes: OpcoesDoContexto = {}
): Promise<ContextoDigital | NextResponse> {
  const supabase = await createClient();
  const {
    data: { user },
  } = await supabase.auth.getUser();
  if (!user) return erroDigital("Sua sessão expirou. Entre de novo.", 401);

  const ctx = await getCompanyContext(supabase, user);
  if (ctx.membership && ctx.membership.active === false) {
    return erroDigital("Seu acesso a esta empresa está desativado.", 403, { motivo: "desativado" });
  }

  const liberado = await digitaisLiberadosAgora([ctx.companyId, ctx.ownerId]);
  if (!liberado && !opcoes.videoDoProduto) {
    return erroDigital("A área de produtos digitais ainda não está liberada para a sua empresa.", 403, { motivo: "nao_liberado" });
  }

  const pode = (chave: CompanyPermission) => canCompany(ctx, user.id, chave);
  const pedidas = Array.isArray(permissao) ? permissao : [permissao];
  /* Quem edita o produto pode pôr o vídeo dele. */
  const exigidas = opcoes.videoDoProduto ? [...pedidas, ...PERMISSOES_DO_PRODUTO] : pedidas;
  if (exigidas.length && !exigidas.some(pode)) {
    return erroDigital("Você não tem permissão para isso. Peça ao responsável da empresa.", 403, { motivo: "sem_permissao" });
  }

  const admin = createAdminClient();
  const lojaId = ctx.ownerId ?? ctx.companyId;

  const assinatura = await assinaturaDaEmpresa(admin, ctx.ownerId || user.id);
  if (!assinatura.ativa) {
    const mensagem =
      MENSAGEM_DA_ASSINATURA[assinatura.situacao] ??
      "A assinatura do Ktalogu desta empresa está inativa. Regularize em Assinatura para usar os produtos digitais.";
    return erroDigital(mensagem, 402, { assinatura: assinatura.situacao });
  }

  return { admin, user, ctx, lojaId, pode, situacao: assinatura.situacao, liberado };
}

/**
 * O invólucro das rotas: abre o contexto, roda e traduz qualquer erro para uma
 * resposta que a tela sabe mostrar. Erro inesperado vira mensagem genérica;
 * o detalhe técnico fica só no log.
 */
export async function rotaDigital(
  permissao: CompanyPermission | CompanyPermission[],
  executar: (contexto: ContextoDigital) => Promise<unknown>,
  opcoes: OpcoesDoContexto = {}
): Promise<Response> {
  const contexto = await abrirContextoDigital(permissao, opcoes);
  if (contexto instanceof NextResponse) return contexto;
  try {
    const resultado = await executar(contexto);
    if (resultado instanceof Response) return resultado;
    return NextResponse.json(resultado ?? { ok: true }, { headers: { "cache-control": "no-store" } });
  } catch (erro) {
    if (erro instanceof ErroDigital) return erroDigital(erro.message, erro.status, erro.extra);
    console.error("[digitais] erro inesperado", erro);
    return erroDigital("Algo deu errado do nosso lado. Tente de novo em instantes.", 500);
  }
}
