import { NextResponse } from "next/server";
import { canCompany, getCompanyContext, type CompanyPermission } from "@/lib/company-context";
import { createAdminClient, createClient } from "@/lib/supabase-server";
import { garantirFornecedorDaXbz } from "@/lib/fornecedores/fornecedor-da-xbz";
import {
  atualizarCatalogoXbz,
  buildXbzDashboardState,
  buscarProdutosXbz,
  cadastrarModeloXbz,
  cancelarPedidoXbz,
  criarPedidoXbz,
  listarPedidosXbz,
  migrateLegacyXbzSettingsToTables,
  salvarCredenciaisEConectarXbz,
  situacaoDoCatalogoXbz,
  syncAuxiliaryXbz,
  testConnectionXbz,
} from "@/lib/xbz/xbz.service";
import type { XbzApiActionBody } from "@/lib/xbz/xbz.types";

/*
  Que permissão cada coisa exige.

  A tela `/dashboard/fornecedores/xbz` abre com `suppliers.read`, mas esta rota
  cobrava `company.settings` até para carregar. Quem tinha uma chave e não a
  outra via o item no menu, entrava e levava 403 já no carregamento — parecia
  defeito do sistema, e não regra de acesso.

  A divisão agora acompanha o que cada ação significa para a empresa: ver é
  ver; mexer na credencial é configuração da empresa; mandar e cancelar pedido
  é gastar dinheiro com fornecedor.

  E "ver" aqui é `suppliers.xbz.read`, a chave DESTA tela, não a do módulo:
  liberar só a XBZ para alguém e a rota continuar cobrando `suppliers.read`
  devolvia a mesma tela vazia de antes. A herança cobre o outro lado — quem
  tem o módulo inteiro continua passando.
*/
function permissaoDaAcao(action: XbzApiActionBody["action"]): CompanyPermission {
  if (action === "saveCredentials" || action === "migrateLegacyData") return "company.settings";
  if (action === "importProduct") return "products.catalog.write";
  if (action === "createOrder" || action === "cancelOrder") return "suppliers.xbz.write";
  return "suppliers.xbz.read";
}

async function getAuthenticatedOwnerId(permission: CompanyPermission) {
  const supabase = await createClient();
  const {
    data: { user },
    error: userError,
  } = await supabase.auth.getUser();

  if (userError || !user) {
    return { error: NextResponse.json({ error: "Não autenticado." }, { status: 401 }) };
  }

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

  /* `ownerId` e `companyId` nao sao a mesma coisa: as empresas antigas nasceram
     com o id igual ao do dono, as novas nao. A integracao e do dono; o cadastro
     de fornecedor e da empresa. */
  return { ownerId: ctx.ownerId || user.id, companyId: ctx.companyId, userId: user.id };
}

export async function GET() {
  try {
    const auth = await getAuthenticatedOwnerId("suppliers.xbz.read");
    if ("error" in auth) return auth.error;
    const state = await buildXbzDashboardState(auth.ownerId);
    return NextResponse.json(state);
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : "Falha ao carregar integração XBZ." },
      { status: 400 }
    );
  }
}

export async function POST(request: Request) {
  try {
    const body = (await request.json()) as XbzApiActionBody;
    const auth = await getAuthenticatedOwnerId(permissaoDaAcao(body.action));
    if ("error" in auth) return auth.error;

    if (body.action === "saveCredentials") {
      const conexao = await salvarCredenciaisEConectarXbz(auth.ownerId, body.cnpj, body.token);

      /* A XBZ passa a existir no cadastro de fornecedores de quem a liga. Sem
         isto, ela continuaria sendo uma ilha dentro do proprio menu
         Fornecedores: produto importado virava produto, mas nada dela entrava
         no historico, na agenda ou nas contas a pagar. */
      const fornecedor = await garantirFornecedorDaXbz(createAdminClient(), auth.companyId, auth.userId);

      const state = await buildXbzDashboardState(auth.ownerId);
      return NextResponse.json({
        ok: true,
        conectado: conexao.conectado,
        message: conexao.mensagem,
        resumo: conexao.resumo,
        fornecedorCriado: fornecedor.criado,
        fornecedorId: fornecedor.supplierId,
        ...state,
      });
    }

    if (body.action === "testConnection") {
      await testConnectionXbz(auth.ownerId);
      return NextResponse.json({
        ok: true,
        message: "A XBZ respondeu. A conexão está funcionando.",
      });
    }

    if (body.action === "syncAuxiliary") {
      const cache = await syncAuxiliaryXbz(auth.ownerId);
      return NextResponse.json({
        ok: true,
        message: "Formas de entrega, de pagamento e transportadoras atualizadas.",
        cache,
      });
    }

    /* A busca lê o catálogo guardado: não gasta consulta da XBZ. */
    if (body.action === "searchProducts") {
      const result = await buscarProdutosXbz(auth.ownerId, body.busca);
      return NextResponse.json({ ok: true, modelos: result.modelos, catalogo: result.catalogo });
    }

    if (body.action === "catalogStatus") {
      const catalogo = await situacaoDoCatalogoXbz(auth.ownerId);
      return NextResponse.json({ ok: true, catalogo });
    }

    if (body.action === "refreshCatalog") {
      const catalogo = await atualizarCatalogoXbz(auth.ownerId);
      return NextResponse.json({
        ok: true,
        message: "Baixando o catálogo da XBZ. Leva uns 30 segundos.",
        catalogo,
      });
    }

    if (body.action === "importProduct") {
      const cadastro = await cadastrarModeloXbz(
        { ownerId: auth.ownerId, companyId: auth.companyId, userId: auth.userId },
        {
          modelo: String(body.modelo ?? ""),
          cores: Array.isArray(body.cores) ? body.cores.map(String).slice(0, 100) : null,
          margem: Number(body.margem),
          nome: typeof body.nome === "string" ? body.nome.slice(0, 200) : null,
        },
        request
      );
      return NextResponse.json({
        ok: true,
        message: cadastro.jaExistia ? "Esse produto já está no seu catálogo." : "Produto cadastrado no catálogo.",
        product: cadastro,
      });
    }

    if (body.action === "createOrder") {
      const result = await criarPedidoXbz(auth.ownerId, {
        pedidoLocalId: body.pedidoLocalId,
        ordemDeCompra: body.ordemDeCompra,
        pagamentoTipoId: body.pagamentoTipoId,
        entregaTipoId: body.entregaTipoId,
        entregaTransportadoraGravacaoId: body.entregaTransportadoraGravacaoId,
        produtoCodigoXbz: body.produtoCodigoXbz,
        quantidade: body.quantidade,
        detalhes: body.detalhes,
      });
      return NextResponse.json({
        ok: true,
        message: result.numero ? `Pedido ${result.numero} criado na XBZ.` : "Pedido enviado para a XBZ.",
        numero: result.numero,
        guardado: result.guardado,
        pedido: result.pedido,
      });
    }

    if (body.action === "listOrders") {
      const { orders, pedidos } = await listarPedidosXbz(auth.ownerId, {
        qtd_dias: body.qtd_dias,
        exibir_finalizados: body.exibir_finalizados,
        exibir_cancelados: body.exibir_cancelados,
        pedido_numero: body.pedido_numero,
      });
      return NextResponse.json({
        ok: true,
        message: "Pedidos consultados com sucesso.",
        orders,
        pedidos,
        syncedAt: new Date().toISOString(),
      });
    }

    if (body.action === "cancelOrder") {
      const result = await cancelarPedidoXbz(auth.ownerId, body.numero);
      return NextResponse.json({
        ok: true,
        message: "Solicitação de cancelamento enviada para XBZ.",
        result,
      });
    }

    /* Ferramenta de manutenção, fora da tela de propósito: converte o formato
       antigo da integração para as tabelas novas. Roda só para a empresa de
       quem chamou. */
    if (body.action === "migrateLegacyData") {
      const result = await migrateLegacyXbzSettingsToTables(auth.ownerId);
      return NextResponse.json({
        ok: true,
        message: "Migração de legado finalizada.",
        result,
      });
    }

    return NextResponse.json({ error: "Ação inválida." }, { status: 400 });
  } catch (error) {
    /* O erro do banco chega como objeto solto, com `message`: lido aqui, a
       pessoa vê o motivo em vez de um "Falha na integração XBZ" genérico. */
    const mensagem =
      error instanceof Error
        ? error.message
        : error && typeof error === "object" && typeof (error as { message?: unknown }).message === "string"
          ? String((error as { message: string }).message)
          : "";
    if (!(error instanceof Error)) console.error("[xbz] erro sem classe na rota:", error);
    return NextResponse.json({ error: mensagem || "Falha na integração XBZ." }, { status: 400 });
  }
}
