import * as kv from "./kv_store.tsx";
import { createLogger } from "./logger.tsx";
import { containsNormalizedText } from './text-normalization.tsx';

const logger = createLogger('Armazens');

// ========== TIPOS ==========

export type TipoArmazem = "principal" | "secundario" | "producao" | "virtual";

export interface Armazem {
  id: string;
  empresaId: string;
  codigo: string; // Código único por empresa (ex: ARM001, ARM002)
  nome: string;
  tipo: TipoArmazem;
  ativo: boolean;
  localizacao?: string; // Endereço ou localização física (opcional)
  observacoes?: string; // Campo livre para anotações gerais
  criadoPor?: string;
  criadoPorNome?: string;
  criadoPorEmail?: string;
  atualizadoPor?: string;
  atualizadoPorNome?: string;
  atualizadoPorEmail?: string;
  dataCriacao: string;
  dataAtualizacao: string;
}

// ========== PREFIXO ==========
const ARMAZENS_PREFIX = "armazem:";
const ARMAZEM_CODIGO_INDEX = "armazem_codigo_index:";

// ========== FUNÇÕES CRUD ==========

/**
 * Criar novo armazém
 */
export async function criarArmazem(
  dados: Omit<Armazem, "id" | "dataCriacao" | "dataAtualizacao">
): Promise<{ success: boolean; data?: Armazem; error?: string }> {
  try {
    // Validar dados obrigatórios
    if (!dados.empresaId || !dados.codigo || !dados.nome || !dados.tipo) {
      return { success: false, error: "Dados obrigatórios faltando" };
    }

    // Verificar se o código já existe para esta empresa
    const codigoExistente = await kv.get(
      `${ARMAZEM_CODIGO_INDEX}${dados.empresaId}:${dados.codigo.toUpperCase()}`
    );
    
    if (codigoExistente) {
      return { 
        success: false, 
        error: `Código '${dados.codigo}' já existe para esta empresa` 
      };
    }

    // Gerar ID único
    const id = `arm_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const agora = new Date().toISOString();

    const armazem: Armazem = {
      id,
      empresaId: dados.empresaId,
      codigo: dados.codigo.toUpperCase(),
      nome: dados.nome,
      tipo: dados.tipo,
      ativo: dados.ativo ?? true,
      localizacao: dados.localizacao,
      observacoes: dados.observacoes,
      criadoPor: (dados as any).criadoPor || (dados as any).usuarioAuditoriaId,
      criadoPorNome: (dados as any).criadoPorNome || (dados as any).usuarioAuditoriaNome,
      criadoPorEmail: (dados as any).criadoPorEmail || (dados as any).usuarioAuditoriaEmail,
      dataCriacao: agora,
      dataAtualizacao: agora,
    };

    // Salvar armazém
    await kv.set(`${ARMAZENS_PREFIX}${id}`, armazem);

    // Criar índice por código
    await kv.set(
      `${ARMAZEM_CODIGO_INDEX}${dados.empresaId}:${armazem.codigo}`,
      id
    );

    logger.info(`Armazém criado: ${armazem.codigo} - ${armazem.nome}`);

    return { success: true, data: armazem };
  } catch (error) {
    logger.error("Erro ao criar armazém:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Buscar armazém por ID
 */
export async function buscarArmazemPorId(id: string, empresaId?: string): Promise<Armazem | null> {
  try {
    if (!id) {
      return null;
    }

    const referencia = String(id).trim();
    const idNormalizado = referencia.startsWith(ARMAZENS_PREFIX)
      ? referencia.slice(ARMAZENS_PREFIX.length)
      : referencia;
    const chave = `${ARMAZENS_PREFIX}${idNormalizado}`;
    logger.debug(`Buscando armazém com chave: "${chave}"`);
    const armazem = await kv.get(chave);
    if (armazem) {
      const armazemData = armazem as Armazem;
      if (empresaId && armazemData.empresaId !== empresaId) {
        return null;
      }
      logger.debug(`Resultado da busca:`, `Encontrado: ${armazemData.codigo} - ${armazemData.nome}`);
      return armazemData;
    }

    const todosArmazens = await kv.getByPrefix<Armazem>(ARMAZENS_PREFIX);
    const referenciaCodigo = referencia.toUpperCase();
    const codigoExtraido = referenciaCodigo.split(/\s+-\s+/)[0]?.trim();
    const fallback = todosArmazens.find((item) => {
      if (!item) return false;
      if (empresaId && item.empresaId !== empresaId) return false;
      return (
        item.id === referencia ||
        item.id === idNormalizado ||
        item.codigo?.toUpperCase() === referenciaCodigo ||
        item.codigo?.toUpperCase() === codigoExtraido
      );
    });

    logger.debug(`Resultado da busca:`, fallback ? `Encontrado por fallback: ${fallback.codigo} - ${fallback.nome}` : 'NÃO ENCONTRADO');
    return fallback || null;
  } catch (error) {
    logger.error("Erro ao buscar armazém:", error);
    return null;
  }
}

/**
 * Buscar armazém por código (dentro de uma empresa)
 */
export async function buscarArmazemPorCodigo(
  empresaId: string,
  codigo: string
): Promise<Armazem | null> {
  try {
    const armazemId = await kv.get(
      `${ARMAZEM_CODIGO_INDEX}${empresaId}:${codigo.toUpperCase()}`
    );
    
    if (!armazemId) {
      return null;
    }

    return await buscarArmazemPorId(armazemId as string, empresaId);
  } catch (error) {
    logger.error("Erro ao buscar armazém por código:", error);
    return null;
  }
}

/**
 * Listar armazéns de uma empresa
 */
export async function listarArmazens(
  empresaId: string,
  filtros?: {
    tipo?: TipoArmazem;
    ativo?: boolean;
    busca?: string;
  }
): Promise<Armazem[]> {
  try {
    const todosArmazens = await kv.getByPrefix<Armazem>(ARMAZENS_PREFIX);
    
    let armazens = todosArmazens.filter((a) => a && a.empresaId === empresaId);

    // Aplicar filtros
    if (filtros?.tipo) {
      armazens = armazens.filter((a) => a.tipo === filtros.tipo);
    }

    if (filtros?.ativo !== undefined) {
      armazens = armazens.filter((a) => a.ativo === filtros.ativo);
    }

    if (filtros?.busca) {
      armazens = armazens.filter(
        (a) =>
          containsNormalizedText(a.codigo, filtros.busca) ||
          containsNormalizedText(a.nome, filtros.busca) ||
          containsNormalizedText(a.localizacao, filtros.busca)
      );
    }

    // Ordenar por código
    armazens.sort((a, b) => a.codigo.localeCompare(b.codigo));

    return armazens;
  } catch (error) {
    logger.error("Erro ao listar armazéns:", error);
    return [];
  }
}

export async function obterOuCriarArmazemZonaQuebra(
  empresaId: string,
): Promise<{ success: boolean; data?: Armazem; error?: string }> {
  try {
    const porCodigo = await buscarArmazemPorCodigo(empresaId, "QUEBRA");
    if (porCodigo) {
      if (!porCodigo.ativo) {
        return await atualizarArmazem(porCodigo.id, { ativo: true, nome: porCodigo.nome || "Zona de Quebra" });
      }
      return { success: true, data: porCodigo };
    }

    const existentes = await listarArmazens(empresaId, { ativo: true });
    const porNome = existentes.find((armazem) =>
      containsNormalizedText(armazem.nome, "zona de quebra") ||
      containsNormalizedText(armazem.nome, "quebra")
    );

    if (porNome) {
      return { success: true, data: porNome };
    }

    return await criarArmazem({
      empresaId,
      codigo: "QUEBRA",
      nome: "Zona de Quebra",
      tipo: "virtual",
      ativo: true,
      observacoes: "Armazém operacional para produtos expirados, avariados ou em retenção antes da perda final.",
    });
  } catch (error) {
    logger.error("Erro ao obter/criar armazém de quebra:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Atualizar armazém
 */
export async function atualizarArmazem(
  id: string,
  dados: Partial<Omit<Armazem, "id" | "empresaId" | "dataCriacao">>
): Promise<{ success: boolean; data?: Armazem; error?: string }> {
  try {
    const armazemExistente = await buscarArmazemPorId(id);

    if (!armazemExistente) {
      return { success: false, error: "Armazém não encontrado" };
    }

    // Se o código está sendo alterado, verificar duplicidade
    if (dados.codigo && dados.codigo.toUpperCase() !== armazemExistente.codigo) {
      const codigoExistente = await kv.get(
        `${ARMAZEM_CODIGO_INDEX}${armazemExistente.empresaId}:${dados.codigo.toUpperCase()}`
      );

      if (codigoExistente && codigoExistente !== id) {
        return {
          success: false,
          error: `Código '${dados.codigo}' já existe para esta empresa`,
        };
      }

      // Remover índice antigo
      await kv.del(
        `${ARMAZEM_CODIGO_INDEX}${armazemExistente.empresaId}:${armazemExistente.codigo}`
      );

      // Criar novo índice
      await kv.set(
        `${ARMAZEM_CODIGO_INDEX}${armazemExistente.empresaId}:${dados.codigo.toUpperCase()}`,
        id
      );
    }

    const armazemAtualizado: Armazem = {
      ...armazemExistente,
      ...dados,
      codigo: dados.codigo?.toUpperCase() || armazemExistente.codigo,
      criadoPor: armazemExistente.criadoPor,
      criadoPorNome: armazemExistente.criadoPorNome,
      criadoPorEmail: armazemExistente.criadoPorEmail,
      atualizadoPor: (dados as any).atualizadoPor || (dados as any).usuarioAuditoriaId,
      atualizadoPorNome: (dados as any).atualizadoPorNome || (dados as any).usuarioAuditoriaNome,
      atualizadoPorEmail: (dados as any).atualizadoPorEmail || (dados as any).usuarioAuditoriaEmail,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${ARMAZENS_PREFIX}${id}`, armazemAtualizado);

    logger.info(`Armazém atualizado: ${armazemAtualizado.codigo}`);

    return { success: true, data: armazemAtualizado };
  } catch (error) {
    logger.error("Erro ao atualizar armazém:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Deletar armazém
 */
export async function deletarArmazem(
  id: string
): Promise<{ success: boolean; error?: string }> {
  try {
    const armazem = await buscarArmazemPorId(id);

    if (!armazem) {
      return { success: false, error: "Armazém não encontrado" };
    }

    // TODO: Verificar se o armazém tem movimentos de stock ou artigos associados
    // Por enquanto, permitir exclusão

    // Remover índice de código
    await kv.del(`${ARMAZEM_CODIGO_INDEX}${armazem.empresaId}:${armazem.codigo}`);

    // Remover armazém
    await kv.del(`${ARMAZENS_PREFIX}${id}`);

    logger.info(`Armazém deletado: ${armazem.codigo}`);

    return { success: true };
  } catch (error) {
    logger.error("Erro ao deletar armazém:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Alternar status ativo/inativo
 */
export async function alternarStatusArmazem(
  id: string
): Promise<{ success: boolean; data?: Armazem; error?: string }> {
  try {
    const armazem = await buscarArmazemPorId(id);

    if (!armazem) {
      return { success: false, error: "Armazém não encontrado" };
    }

    const armazemAtualizado: Armazem = {
      ...armazem,
      ativo: !armazem.ativo,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${ARMAZENS_PREFIX}${id}`, armazemAtualizado);

    logger.info(
      `Status alterado: ${armazemAtualizado.codigo} - ${
        armazemAtualizado.ativo ? "ATIVO" : "INATIVO"
      }`
    );

    return { success: true, data: armazemAtualizado };
  } catch (error) {
    logger.error("Erro ao alternar status:", error);
    return { success: false, error: error.message };
  }
}

/**
 * Obter estatísticas de armazéns
 */
export async function obterEstatisticasArmazens(empresaId: string): Promise<{
  total: number;
  ativos: number;
  inativos: number;
  porTipo: Record<TipoArmazem, number>;
}> {
  try {
    const armazens = await listarArmazens(empresaId);

    const stats = {
      total: armazens.length,
      ativos: armazens.filter((a) => a.ativo).length,
      inativos: armazens.filter((a) => !a.ativo).length,
      porTipo: {
        principal: 0,
        secundario: 0,
        producao: 0,
        virtual: 0,
      } as Record<TipoArmazem, number>,
    };

    armazens.forEach((a) => {
      stats.porTipo[a.tipo]++;
    });

    return stats;
  } catch (error) {
    logger.error("Erro ao obter estatísticas:", error);
    return {
      total: 0,
      ativos: 0,
      inativos: 0,
      porTipo: {
        principal: 0,
        secundario: 0,
        producao: 0,
        virtual: 0,
      },
    };
  }
}
