import { createClient } from "../../src/compat/supabase.js";
import * as kv from "./kv_store.tsx";
import { isValidNuit, normalizeNuit } from "./nuit.tsx";

// Entidade paralela a Usuario (usuarios.tsx), mas sem empresaId/nivel/
// permissoes - um Revendedor nao pertence a nenhuma empresa do ERP, e uma
// pessoa externa que ganha comissao por referir empresas. Segue o mesmo
// padrao "criar no Supabase Auth, espelhar no KV" ja usado em criarUsuario.

export interface Revendedor {
  id: string; // = authUserId
  authUserId: string;
  email: string;
  nome: string;
  nuit: string;
  telefone: string;
  provincia?: string;
  distrito?: string;
  bairro?: string;
  fotoUrl?: string;
  numeroMpesa: string;
  // Quando o número M-Pesa foi alterado pela última vez (nunca no cadastro
  // inicial, só via atualizarNumeroMpesa) - usado para aplicar um período de
  // tolerância antes de permitir um novo levantamento com o número novo,
  // já que mudar o destino do dinheiro é o vector de fraude mais provável
  // aqui (ver levantamentos-revendedor.tsx).
  numeroMpesaAlteradoEm?: string;
  codigoReferencia: string;
  ativo: boolean;
  dataCriacao: string;
}

export interface ComissaoRevendedor {
  id: string;
  revendedorId: string;
  empresaId: string;
  movimentoFinanceiroId?: string;
  valorBase: number;
  percentual: number;
  valorComissao: number;
  dataCriacao: string;
}

interface ConfigRevendedores {
  percentualComissao: number;
  ativo: boolean;
}

const CONFIG_REVENDEDORES_KEY = "revendedores:config:v1";
const DEFAULT_CONFIG_REVENDEDORES: ConfigRevendedores = {
  percentualComissao: 15,
  ativo: true,
};

function supabaseAdminClient() {
  return createClient(
    Deno.env.get("SUPABASE_URL") ?? "",
    Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "",
  );
}

function gerarSufixoAleatorio(tamanho: number): string {
  const digitos = "0123456789";
  let resultado = "";
  for (let i = 0; i < tamanho; i++) {
    resultado += digitos[Math.floor(Math.random() * digitos.length)];
  }
  return resultado;
}

async function gerarCodigoReferenciaUnico(nome: string): Promise<string> {
  const base = String(nome || "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .replace(/[^a-zA-Z0-9]/g, "")
    .slice(0, 10)
    .toUpperCase() || "REVENDEDOR";

  for (let tentativa = 0; tentativa < 10; tentativa++) {
    const codigo = `${base}${gerarSufixoAleatorio(4)}`;
    const existente = await kv.get(`revendedor:codigo:${codigo}`);
    if (!existente) {
      return codigo;
    }
  }

  // Fallback extremamente improvável de acontecer, mas garante que a função
  // nunca fica presa em loop.
  return `${base}${Date.now()}`;
}

export async function criarRevendedor(dados: {
  email: string;
  password: string;
  nome: string;
  nuit: string;
  telefone: string;
  numeroMpesa: string;
  provincia?: string;
  distrito?: string;
  bairro?: string;
}): Promise<{ success: boolean; data?: Revendedor; error?: string }> {
  try {
    const emailNormalizado = String(dados.email || "").trim().toLowerCase();
    const nuitNormalizado = normalizeNuit(dados.nuit);
    const nome = String(dados.nome || "").trim();
    const telefone = String(dados.telefone || "").trim();
    const numeroMpesa = String(dados.numeroMpesa || "").trim();

    if (!emailNormalizado || !dados.password || !nome || !telefone || !numeroMpesa) {
      return { success: false, error: "Dados obrigatórios em falta" };
    }
    if (dados.password.length < 6) {
      return { success: false, error: "Senha deve ter pelo menos 6 caracteres" };
    }
    if (!isValidNuit(nuitNormalizado)) {
      return { success: false, error: "NUIT inválido" };
    }

    const existente = await buscarRevendedorPorEmail(emailNormalizado);
    if (existente) {
      return { success: false, error: "Já existe um revendedor com este email" };
    }

    const supabase = supabaseAdminClient();
    const { data: authData, error: authError } = await supabase.auth.admin.createUser({
      email: emailNormalizado,
      password: dados.password,
      email_confirm: true,
      user_metadata: {
        nome,
        tipo: "revendedor",
      },
    });

    if (authError || !authData?.user) {
      return { success: false, error: authError?.message || "Erro ao criar autenticação" };
    }

    const revendedorId = authData.user.id;
    const codigoReferencia = await gerarCodigoReferenciaUnico(nome);

    const revendedor: Revendedor = {
      id: revendedorId,
      authUserId: revendedorId,
      email: emailNormalizado,
      nome,
      nuit: nuitNormalizado,
      telefone,
      provincia: dados.provincia?.trim() || undefined,
      distrito: dados.distrito?.trim() || undefined,
      bairro: dados.bairro?.trim() || undefined,
      numeroMpesa,
      codigoReferencia,
      ativo: true,
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`revendedor:${revendedorId}`, revendedor);
    await kv.set(`revendedor:email:${emailNormalizado}`, revendedorId);
    await kv.set(`revendedor:codigo:${codigoReferencia}`, revendedorId);

    return { success: true, data: revendedor };
  } catch (error: any) {
    return { success: false, error: error.message || String(error) };
  }
}

export async function buscarRevendedorPorEmail(email: string): Promise<Revendedor | null> {
  try {
    const emailNormalizado = String(email || "").trim().toLowerCase();
    if (!emailNormalizado) return null;

    const revendedorId = await kv.get(`revendedor:email:${emailNormalizado}`);
    if (!revendedorId) return null;

    return (await kv.get(`revendedor:${revendedorId}`)) as Revendedor | null;
  } catch (_error) {
    return null;
  }
}

export async function buscarRevendedorPorId(id: string): Promise<Revendedor | null> {
  try {
    if (!id) return null;
    return (await kv.get(`revendedor:${id}`)) as Revendedor | null;
  } catch (_error) {
    return null;
  }
}

export async function buscarRevendedorPorCodigo(codigo: string): Promise<Revendedor | null> {
  try {
    const codigoNormalizado = String(codigo || "").trim().toUpperCase();
    if (!codigoNormalizado) return null;

    const revendedorId = await kv.get(`revendedor:codigo:${codigoNormalizado}`);
    if (!revendedorId) return null;

    return (await kv.get(`revendedor:${revendedorId}`)) as Revendedor | null;
  } catch (_error) {
    return null;
  }
}

// Paralelo a obterUsuarioAutenticadoRequest (admin-shared-helpers.tsx): lê o
// X-User-Token, valida contra o Supabase Auth (mesmo projecto, client
// anon-key), e resolve o registo de Revendedor em vez do de Usuario.
export async function obterRevendedorAutenticadoRequest(c: any): Promise<Revendedor | null> {
  const accessToken = c.req.header("X-User-Token");
  if (!accessToken) return null;

  const supabaseUrl = Deno.env.get("SUPABASE_URL") ?? "";
  const anonKey = Deno.env.get("SUPABASE_ANON_KEY") ?? "";
  const supabase = createClient(supabaseUrl, anonKey);
  const { data: { user }, error } = await supabase.auth.getUser(accessToken);

  if (error || !user?.email) {
    return null;
  }

  return await buscarRevendedorPorEmail(user.email);
}

export async function obterConfigRevendedores(): Promise<ConfigRevendedores> {
  const config = (await kv.get(CONFIG_REVENDEDORES_KEY)) as Partial<ConfigRevendedores> | null;
  if (!config) return { ...DEFAULT_CONFIG_REVENDEDORES };

  return {
    percentualComissao:
      typeof config.percentualComissao === "number"
        ? config.percentualComissao
        : DEFAULT_CONFIG_REVENDEDORES.percentualComissao,
    ativo: config.ativo !== false,
  };
}

// Personalização pela Tonline (aba "Planos e Pagamentos" da Gestão TONLINE) -
// o percentual é sempre sobre o valor da avença, nunca sobre a taxa de
// inscrição/licença (ver os pontos onde registrarComissaoSeAplicavel é
// chamada: usam sempre plano.avencaTotal/valorRecorrente, nunca o total da
// subscrição).
export async function atualizarConfigRevendedores(
  dados: Partial<ConfigRevendedores>,
): Promise<{ success: boolean; data?: ConfigRevendedores; error?: string }> {
  const percentualComissao = Number(dados.percentualComissao);
  if (!Number.isFinite(percentualComissao) || percentualComissao < 0 || percentualComissao > 100) {
    return { success: false, error: "Percentual de comissão inválido (deve ser entre 0 e 100)" };
  }

  const config: ConfigRevendedores = {
    percentualComissao,
    ativo: dados.ativo !== false,
  };

  await kv.set(CONFIG_REVENDEDORES_KEY, config);
  return { success: true, data: config };
}

// Função central e reutilizável: chamada a partir de todos os pontos onde um
// pagamento de subscrição é confirmado (signup inicial + renovações manuais
// e automáticas), para nunca duplicar a regra de negócio em cada um deles.
// Não faz nada (silenciosamente) se a empresa não tiver sido referida por
// nenhum revendedor - a maioria dos pagamentos passa por aqui sem efeito.
export async function registrarComissaoSeAplicavel(
  empresaId: string,
  valorPago: number,
  movimentoFinanceiroId?: string,
): Promise<{ registrou: boolean; comissao?: ComissaoRevendedor }> {
  try {
    if (!empresaId || !valorPago || valorPago <= 0) return { registrou: false };

    const empresa = (await kv.get(`empresa:${empresaId}`)) as { referidoPor?: string } | null;
    if (!empresa?.referidoPor) return { registrou: false };

    const config = await obterConfigRevendedores();
    if (!config.ativo) return { registrou: false };

    const revendedor = await buscarRevendedorPorId(empresa.referidoPor);
    if (!revendedor || !revendedor.ativo) return { registrou: false };

    const valorComissao = Math.round(((valorPago * config.percentualComissao) / 100) * 100) / 100;
    const id = `com_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;

    const comissao: ComissaoRevendedor = {
      id,
      revendedorId: revendedor.id,
      empresaId,
      movimentoFinanceiroId,
      valorBase: valorPago,
      percentual: config.percentualComissao,
      valorComissao,
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`comissao_revendedor:${id}`, comissao);

    // Contador de saldo simples - o histórico individual fica em
    // comissao_revendedor:*, não precisa de ser somado a cada leitura (a
    // comissão é recorrente para sempre, o histórico cresce sem limite).
    // IMPORTANTE: preservar totalLevantado ao reescrever este registo -
    // nunca reconstruir o objecto só com totalGanho, ou um levantamento já
    // feito "desaparece" da conta na próxima comissão.
    const saldoActual = (await kv.get(`revendedor_saldo:${revendedor.id}`)) as
      | { totalGanho?: number; totalLevantado?: number }
      | null;
    await kv.set(`revendedor_saldo:${revendedor.id}`, {
      totalGanho: (saldoActual?.totalGanho || 0) + valorComissao,
      totalLevantado: saldoActual?.totalLevantado || 0,
    });

    return { registrou: true, comissao };
  } catch (_error) {
    return { registrou: false };
  }
}

// Chamada só pelo fluxo de levantamento (levantamentos-revendedor.tsx) depois
// de o B2C confirmar sucesso - nunca decrementar o saldo antes da confirmação
// real da Vodacom, para não perder dinheiro em caso de falha a meio.
export async function registrarLevantamentoConcluido(revendedorId: string, valor: number): Promise<void> {
  const saldoActual = (await kv.get(`revendedor_saldo:${revendedorId}`)) as
    | { totalGanho?: number; totalLevantado?: number }
    | null;
  await kv.set(`revendedor_saldo:${revendedorId}`, {
    totalGanho: saldoActual?.totalGanho || 0,
    totalLevantado: (saldoActual?.totalLevantado || 0) + valor,
  });
}

export async function obterSaldoRevendedor(
  revendedorId: string,
): Promise<{ totalGanho: number; totalLevantado: number; saldoDisponivel: number }> {
  const saldo = (await kv.get(`revendedor_saldo:${revendedorId}`)) as
    | { totalGanho?: number; totalLevantado?: number }
    | null;
  const totalGanho = saldo?.totalGanho || 0;
  const totalLevantado = saldo?.totalLevantado || 0;
  return {
    totalGanho,
    totalLevantado,
    saldoDisponivel: Math.max(0, Math.round((totalGanho - totalLevantado) * 100) / 100),
  };
}

const NUMERO_MPESA_REGEX = /^8[45]\d{7}$/;

// Alterar o número M-Pesa é a única acção que muda o destino real do dinheiro
// de um revendedor - por isso vive à parte do cadastro (nunca editável no
// próprio fluxo de levantamento, só aqui) e marca numeroMpesaAlteradoEm para
// o período de tolerância aplicado em levantamentos-revendedor.tsx.
export async function atualizarNumeroMpesa(
  revendedorId: string,
  novoNumero: string,
): Promise<{ success: boolean; data?: Revendedor; error?: string }> {
  const numeroNormalizado = String(novoNumero || "").replace(/\D/g, "");
  if (!NUMERO_MPESA_REGEX.test(numeroNormalizado)) {
    return { success: false, error: "Número M-Pesa inválido. Use um número Vodacom iniciado por 84 ou 85 (9 dígitos)" };
  }

  const revendedor = await buscarRevendedorPorId(revendedorId);
  if (!revendedor) {
    return { success: false, error: "Revendedor não encontrado" };
  }

  const atualizado: Revendedor = {
    ...revendedor,
    numeroMpesa: numeroNormalizado,
    numeroMpesaAlteradoEm: new Date().toISOString(),
  };

  await kv.set(`revendedor:${revendedorId}`, atualizado);
  return { success: true, data: atualizado };
}
