import * as kv from "./kv_store.tsx";
import { createLogger } from "./logger.tsx";
import { isValidNuit, normalizeNuit } from "./nuit.tsx";

const logger = createLogger('Clientes');

// ========== TIPOS ==========

export interface ClienteNomeFacturacao {
  id: string;
  nome: string;
  endereco?: string;
  ativo: boolean;
}

function slugifyNomeFacturacao(value: string): string {
  return value
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 40);
}

function normalizarNomesFacturacao(
  nomesFacturacao: ClienteNomeFacturacao[] | undefined,
  nomePrincipal: string,
): ClienteNomeFacturacao[] {
  const nomePrincipalNormalizado = nomePrincipal.trim().toLowerCase();
  const usados = new Set<string>();

  return (nomesFacturacao || [])
    .map((item, index) => {
      const nome = item?.nome?.trim() || "";
      if (!nome) return null;
      if (nome.toLowerCase() === nomePrincipalNormalizado) return null;

      const endereco = item?.endereco?.trim() || "";
      const chave = `${nome.toLowerCase()}|${endereco.toLowerCase()}`;
      if (usados.has(chave)) return null;
      usados.add(chave);

      return {
        id: item?.id?.trim() || slugifyNomeFacturacao(nome) || `nome-facturacao-${index + 1}`,
        nome,
        endereco: endereco || undefined,
        ativo: item?.ativo !== false,
      };
    })
    .filter((item): item is ClienteNomeFacturacao => item !== null);
}

export interface Cliente {
  id: string;
  empresaId: string; // Multi-tenant: cada empresa tem seus clientes
  codigo: string; // Código interno (ex: CLI001)
  nome: string;
  nomeComercial?: string;
  nomesFacturacao?: ClienteNomeFacturacao[];
  nuit: string; // NUIT obrigatório em Moçambique
  email?: string;
  telefone?: string;
  telemovel?: string;
  endereco?: string;
  cidade?: string;
  provincia?: string;
  pais: string;
  observacoes?: string;
  ativo: boolean;
  dataCriacao: string;
  dataAtualizacao?: string;
  // ✅ NOVO: Campos financeiros
  prazoPagamento?: number; // dias
  limiteCredito?: number;
  bloqueioVendasAposXDias?: number;
  formasPagamentoPreferidas?: string[];
  descontoPercentual?: number;
  observacoesFinanceiras?: string;
}

// ========== FUNÇÕES DE GESTÃO DE CLIENTES ==========

/**
 * Gerar código automático para cliente
 */
async function gerarCodigoCliente(empresaId: string): Promise<string> {
  const clientes = await listarClientes(empresaId);
  const proximoNumero = clientes.length + 1;
  return `CLI${proximoNumero.toString().padStart(4, '0')}`; // CLI0001, CLI0002, etc
}

/**
 * Criar novo cliente
 */
export async function criarCliente(dados: Omit<Cliente, 'id' | 'codigo' | 'dataCriacao'>): Promise<{ success: boolean; data?: Cliente; error?: string }> {
  try {
    const nuitNormalizado = normalizeNuit(dados.nuit);

    // Validar dados obrigatórios
    if (!dados.empresaId || !dados.nome || !nuitNormalizado) {
      return { success: false, error: "Empresa, nome e NUIT são obrigatórios" };
    }

    if (!isValidNuit(nuitNormalizado)) {
      return { success: false, error: "NUIT inválido. Deve conter exatamente 9 dígitos numéricos" };
    }

    // Verificar se NUIT já existe na empresa
    const clienteExistente = await buscarClientePorNuit(dados.empresaId, nuitNormalizado);
    if (clienteExistente) {
      return { success: false, error: "Já existe um cliente com este NUIT" };
    }

    // ✅ CORREÇÃO: Gerar ID com prefixo "cliente:" desde o início
    const timestamp = Date.now();
    const random = Math.random().toString(36).substr(2, 9);
    const id = `cliente:${dados.empresaId}:${timestamp}_${random}`; // Formato: cliente:empresaId:timestamp_random
    const codigo = await gerarCodigoCliente(dados.empresaId);

    // ✅ ...dados vem ANTES de id/codigo: se o pedido incluir estes campos
    // (ex: um "codigo" pre-visualizado no frontend antes de gravar, ou vazio
    // por uma corrida entre a geracao automatica e o submit), o spread de
    // dados nao pode sobrepor-se ao id/codigo gerados aqui no servidor.
    const cliente: Cliente = {
      ...dados,
      id,
      codigo,
      nome: dados.nome.trim(),
      nomesFacturacao: normalizarNomesFacturacao(dados.nomesFacturacao, dados.nome),
      nuit: nuitNormalizado,
      pais: dados.pais || "Moçambique",
      ativo: dados.ativo !== undefined ? dados.ativo : true,
      dataCriacao: new Date().toISOString(),
    };

    // ✅ CORREÇÃO: Salvar com o ID completo (que já tem prefixo)
    await kv.set(id, cliente);
    
    // Indexar por NUIT para busca rápida
    await kv.set(`cliente_nuit:${dados.empresaId}:${nuitNormalizado}`, id);

    logger.info(`Cliente criado: ${codigo} - ${dados.nome}`);

    return { success: true, data: cliente };
  } catch (error) {
    logger.error("Erro ao criar cliente:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Buscar cliente por ID
 */
export async function buscarClientePorId(id: string): Promise<Cliente | null> {
  try {
    const cliente = await kv.get(id);
    return cliente as Cliente | null;
  } catch (error) {
    logger.error("Erro ao buscar cliente:", error);
    return null;
  }
}

/**
 * Buscar cliente por NUIT
 */
export async function buscarClientePorNuit(empresaId: string, nuit: string): Promise<Cliente | null> {
  try {
    const clienteId = await kv.get(`cliente_nuit:${empresaId}:${normalizeNuit(nuit)}`);
    if (!clienteId) return null;

    return await buscarClientePorId(clienteId as string);
  } catch (error) {
    logger.error("Erro ao buscar cliente por NUIT:", error);
    return null;
  }
}

/**
 * Listar clientes de uma empresa
 */
export async function listarClientes(empresaId: string, filtros?: { ativo?: boolean }): Promise<Cliente[]> {
  try {
    const todosClientes = await kv.getByPrefix<Cliente>("cliente:");
    
    let clientes = todosClientes.filter((c) => c && c.empresaId === empresaId);

    // Aplicar filtro de status se fornecido
    if (filtros?.ativo !== undefined) {
      clientes = clientes.filter((c) => c.ativo === filtros.ativo);
    }

    // Ordenar por código
    clientes.sort((a, b) => a.codigo.localeCompare(b.codigo));

    return clientes;
  } catch (error) {
    logger.error("Erro ao listar clientes:", error);
    return [];
  }
}

/**
 * Atualizar cliente
 */
export async function atualizarCliente(
  id: string,
  dados: Partial<Cliente>
): Promise<{ success: boolean; data?: Cliente; error?: string }> {
  try {
    const cliente = await buscarClientePorId(id);
    
    if (!cliente) {
      return { success: false, error: "Cliente não encontrado" };
    }

    // Se está alterando o NUIT, verificar se não existe outro com o mesmo NUIT
    const nuitAtualizado = dados.nuit !== undefined ? normalizeNuit(dados.nuit) : undefined;

    if (dados.nuit !== undefined) {
      if (!nuitAtualizado) {
        return { success: false, error: "NUIT é obrigatório" };
      }

      if (!isValidNuit(nuitAtualizado)) {
        return { success: false, error: "NUIT inválido. Deve conter exatamente 9 dígitos numéricos" };
      }
    }

    if (nuitAtualizado && nuitAtualizado !== cliente.nuit) {
      const nuitExiste = await buscarClientePorNuit(cliente.empresaId, nuitAtualizado);
      if (nuitExiste) {
        return { success: false, error: "Já existe um cliente com este NUIT" };
      }

      // Remover índice antigo
      await kv.del(`cliente_nuit:${cliente.empresaId}:${cliente.nuit}`);
      
      // Adicionar novo índice
      await kv.set(`cliente_nuit:${cliente.empresaId}:${nuitAtualizado}`, id);
    }

    // Atualizar cliente
    const clienteAtualizado: Cliente = {
      ...cliente,
      ...dados,
      ...(dados.nome !== undefined ? { nome: dados.nome.trim() } : {}),
      nomesFacturacao: normalizarNomesFacturacao(
        dados.nomesFacturacao !== undefined ? dados.nomesFacturacao : cliente.nomesFacturacao,
        dados.nome !== undefined ? dados.nome : cliente.nome,
      ),
      ...(nuitAtualizado ? { nuit: nuitAtualizado } : {}),
      id: cliente.id, // Garantir que ID não muda
      codigo: cliente.codigo, // Garantir que código não muda
      empresaId: cliente.empresaId, // Garantir que empresaId não muda
      dataCriacao: cliente.dataCriacao, // Manter data de criação original
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(id, clienteAtualizado);

    logger.info(`Cliente atualizado: ${clienteAtualizado.codigo}`);

    return { success: true, data: clienteAtualizado };
  } catch (error) {
    logger.error("Erro ao atualizar cliente:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Excluir cliente (soft delete - apenas marca como inativo)
 */
export async function excluirCliente(id: string): Promise<{ success: boolean; error?: string }> {
  try {
    const cliente = await buscarClientePorId(id);
    
    if (!cliente) {
      return { success: false, error: "Cliente não encontrado" };
    }

    // Soft delete: apenas marcar como inativo
    return await atualizarCliente(id, { ativo: false });
  } catch (error) {
    logger.error("Erro ao excluir cliente:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Ativar/Desativar cliente
 */
export async function toggleAtivo(id: string, ativo: boolean): Promise<{ success: boolean; data?: Cliente; error?: string }> {
  return await atualizarCliente(id, { ativo });
}
