import api from './api';
import { handleRequest, simulateLatency } from './serviceUtils';
import { MOCK_BOLETOS, MOCK_CLIENTS, MOCK_SERVICES } from '../features/workspace/mockData';

/**
 * @typedef {Object} Boleto
 * @property {string} codigoSolicitacao
 * @property {string} seuNumero
 * @property {string} dataEmissao
 * @property {string} dataVencimento
 * @property {string} dataSituacao
 * @property {number} valorNominal
 * @property {number|string} [valorTotalRecebido]
 * @property {string} situacao
 * @property {string} origemRecebimento
 * @property {string} tipoCobranca
 * @property {Object} pagador
 * @property {string} pagador.nome
 * @property {string} pagador.email
 * @property {string} pagador.cpfCnpj
 */

/**
 * @typedef {Object} ExtratoItem
 * @property {number} idextrato
 * @property {string} dataEntrada
 * @property {string} descricao
 * @property {number|string} valor
 * @property {string} tipoOperacao - "C" (Crédito) ou "D" (Débito)
 * @property {string} titulo
 */

/**
 * @typedef {Object} Cliente
 * @property {number} idempresa
 * @property {string} nome
 * @property {string} nome_exibicao
 * @property {string} cpf_cnpj
 * @property {string} status
 * @property {number} valor_servico
 */

/**
 * @typedef {Object} Servico
 * @property {number} idservicos
 * @property {string} servico
 * @property {number} valor
 */

/**
 * Service de Receitas para o ambiente Workspace
 * Gerencia comunicação com as rotas de boletos, clientes e serviços
 * Baseado na lógica antiga do sistema de boletos do Inter
 */
export const workspaceReceitasService = {
  /**
   * Busca boletos com seus status
   * Baseado na lógica antiga: Consult_POST com OPTIONS e GET
   * A lógica antiga fazia duas requisições:
   * - OPTIONS /boletos/status (Boletos_OPTIONS)
   * - GET /boletos/status (Boletos_GET)
   * @returns {Promise<{Boletos_GET: {cobrancas: Array<{cobranca: Boleto}>}}>}
   */
  fetchBoletos: () => handleRequest({
    mockFn: () => simulateLatency({
      Boletos_GET: {
        cobrancas: MOCK_BOLETOS.map(b => ({
          cobranca: {
            codigoSolicitacao: b.id?.toString() || '',
            seuNumero: '',
            dataEmissao: b.dataEmissao || '',
            dataVencimento: b.vencimento || '',
            dataSituacao: '',
            valorNominal: b.valor || 0,
            valorTotalRecebido: b.status === 'Pago' ? b.valor : null,
            situacao: b.status === 'Pago' ? 'RECEBIDO' : b.status === 'Atrasado' ? 'ATRASADO' : 'A_RECEBER',
            origemRecebimento: 'BOLETO',
            tipoCobranca: 'SIMPLES',
            pagador: {
              nome: b.cliente || '',
              email: '',
              cpfCnpj: ''
            }
          }
        }))
      }
    }),
    apiFn: async () => {
      // O usuário solicitou OPTIONS seguido de GET para apresentação
      try {
        await api.options('/boletos/status');
      } catch (err) {
        console.warn('[workspaceReceitasService] OPTIONS /boletos/status failed:', err);
      }
      
      const response = await api.get('/boletos/status');
      
      // Normalização: se vier a estrutura antiga (Boletos_GET), mantém. 
      // Se vier a nova (cobrancas no root), retorna o objeto inteiro para que o chamador decida.
      return response.data;
    }
  }),

  /**
   * Busca extrato bancário
   * Rota: GET /extrato/apresentar
   * Usado para fazer cruzamento com boletos e identificar PIX recebidos sem boleto correspondente
   * @returns {Promise<ExtratoItem[]>}
   */
  fetchExtrato: () => handleRequest({
    mockFn: () => simulateLatency([
      { idextrato: 1, dataEntrada: '2026-01-15', descricao: 'PIX RECEBIDO - CLIENTE XYZ', valor: 1500.00, tipoOperacao: 'C', titulo: 'Pix recebido' },
      { idextrato: 2, dataEntrada: '2026-01-16', descricao: 'PIX RECEBIDO - CLIENTE ABC', valor: 2500.00, tipoOperacao: 'C', titulo: 'Pix recebido' },
    ]),
    apiFn: async () => {
      const response = await api.get('/extrato/apresentar');
      // Retorna array de itens do extrato
      const data = Array.isArray(response.data) ? response.data : (response.data?.Base_Dados_API || []);
      return data;
    }
  }),

  /**
   * Busca lista de clientes/empresas
   * Rota: GET /empresas_financeiro
   * Retorna formato compatível com ClientsView: idempresa, nome, nome_exibicao, email, cpf_cnpj, etc.
   * @returns {Promise<Cliente[]>}
   */
  fetchClientes: () => handleRequest({
    mockFn: () => simulateLatency(
      (MOCK_CLIENTS || []).map(c => ({
        id: c.id,
        idempresa: c.id,
        nome: c.nome,
        nome_exibicao: c.nome,
        email: '',
        cpf_cnpj: c.cnpj || '',
        status: c.status || 'Ativo',
        status_serv: c.status || 'Ativo',
        valor_servico: c.total_faturado ?? 0,
        ...c
      }))
    ),
    apiFn: async () => {
      const response = await api.get('/empresas_financeiro');
      const raw = response?.data;
      let list = [];
      if (Array.isArray(raw)) {
        list = raw;
      } else if (raw?.Base_Dados_API !== undefined) {
        const base = raw.Base_Dados_API;
        list = Array.isArray(base) ? base : (typeof base === 'object' && base !== null ? Object.values(base) : []);
      } else if (raw && typeof raw === 'object') {
        list = Object.values(raw);
      }
      // Normalização alinhada à lógica antiga Clientes_Detalhe (Empresa): Base_Dados_API → list_cobranca, filtro por status
      return list.map(item => ({
        id: item.idempresa ?? item.id,
        idempresa: item.idempresa ?? item.id,
        nome: item.nome ?? item.nome_exibicao ?? '',
        nome_exibicao: item.nome_exibicao ?? item.nome ?? '',
        email: item.email ?? '',
        cpf_cnpj: item.cpf_cnpj ?? item.cnpj ?? '',
        telefone: item.telefone ?? '',
        endereco: item.endereco ?? '',
        bairro: item.bairro ?? '',
        cidade: item.cidade ?? '',
        uf: item.uf ?? '',
        cep: item.cep ?? '',
        status: item.status ?? item.status_serv ?? 'Ativo',
        status_serv: item.status_serv ?? item.status ?? 'Ativo',
        valor_servico: item.valor_servico ?? item.total_faturado ?? 0,
        dominio: item.dominio ?? '',
        obs: item.obs ?? '',
        data_vencimento: item.data_vencimento ?? '',
        tipo_pessoa: item.tipo_pessoa ?? '',
        ...item
      }));
    }
  }),

  /**
   * Cria novo cliente/empresa
   * Rota: POST /empresas_financeiro/create
   * @param {Object} payload - Dados completos do cliente
   * @returns {Promise<any>}
   */
  createClient: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true, idempresa: Date.now() }),
    apiFn: async () => {
      const response = await api.post('/empresas_financeiro/create', payload);
      return response.data;
    }
  }),

  /**
   * Edita cliente/empresa existente
   * Rota: POST /empresas_financeiro/edit
   * @param {Object} payload - Dados completos do cliente (incluindo idempresa)
   * @returns {Promise<any>}
   */
  updateClient: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.post('/empresas_financeiro/edit', payload);
      return response.data;
    }
  }),

  /**
   * Atualiza status do cliente (Ativo/Inativo)
   * Rota: POST /empresas_financeiro/status
   * @param {Object} payload - { status: "Ativo" | "Inativo", idempresa: number, data_envio?: "YYYY-M-D" }
   * @returns {Promise<any>}
   */
  updateClientStatus: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.post('/empresas_financeiro/status', payload);
      return response.data;
    }
  }),

  /**
   * Busca lista de serviços
   * Rota: GET /servicos/list ou GET /servicos/list?tipo=servico|produto
   * Baseado na lógica antiga: item.Nome === "Servicos", Base_Dados_API (objeto ou array) → list_cobranca
   * Retorna formato esperado por ServicesView: idservicos, servico, valor, descricao
   * @param {string} [tipo] - Filtro opcional: 'servico', 'produto', ou undefined para todos
   * @returns {Promise<Array<{idservicos: number, servico: string, valor: number, descricao?: string}>>}
   */
  fetchServicos: (tipo) => handleRequest({
    mockFn: () => simulateLatency(
      (MOCK_SERVICES || []).map(s => ({
        idservicos: s.id ?? s.idservicos,
        servico: s.descricao ?? s.servico ?? '',
        valor: Number(s.preco_base ?? s.valor ?? 0),
        descricao: s.descricao ?? s.servico ?? '',
        categoria: s.categoria,
        imagem: s.imagem ?? '',
        ...s
      }))
    ),
    apiFn: async () => {
      const url = tipo ? `/servicos/list?tipo=${tipo}` : '/servicos/list';
      const response = await api.get(url);
      const raw = response?.data;
      let servicesList = [];
      let baseData = [];

      if (Array.isArray(raw)) {
        baseData = raw;
      } else if (raw?.Base_Dados_API !== undefined) {
        const base = raw.Base_Dados_API;
        baseData = Array.isArray(base) ? base : (typeof base === 'object' && base !== null ? Object.values(base) : []);
      } else if (raw && typeof raw === 'object') {
        baseData = Object.values(raw);
      }

      // Verifica se a estrutura é aninhada: [{ tipo_servico, servicos: [] }, ...]
      const isNested = baseData.length > 0 && baseData.some(item => item.servicos && Array.isArray(item.servicos));

      if (isNested) {
        baseData.forEach(group => {
          if (group.servicos && Array.isArray(group.servicos)) {
            group.servicos.forEach(svc => {
              servicesList.push({
                ...svc,
                tipo_servico: group.tipo_servico || 'Serviço'
              });
            });
          } else if (typeof group === 'object' && group !== null) {
            // Caso tenha itens soltos no meio do array aninhado (improvável mas possível)
            servicesList.push(group);
          }
        });
      } else {
        servicesList = baseData;
      }

      return servicesList.map(item => ({
        idservicos: item.idservicos ?? item.id,
        servico: item.servico ?? item.descricao ?? '',
        valor: Number(item.valor ?? item.preco_base ?? 0),
        descricao: item.descricao ?? item.servico ?? '',
        categoria: item.categoria || 'Geral',
        imagem: item.imagem ?? '',
        tipo_servico: item.tipo_servico || 'Serviço',
        ...item
      }));
    }
  }),

  /**
   * Cria serviço
   * Rota: POST /servicos/create
   * @param {Object} payload - { servico, valor, imagem?, data_envio? }
   */
  createServico: (payload) => handleRequest({
    mockFn: () => simulateLatency({ idservicos: 999, ...payload }),
    apiFn: async () => {
      const response = await api.post('/servicos/create', payload);
      return response.data;
    }
  }),

  /**
   * Edita serviço
   * Rota: POST /servicos/edit
   * @param {Object} payload - { idservicos, servico, valor, imagem?, data_envio? }
   */
  editServico: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.post('/servicos/edit', payload);
      return response.data;
    }
  }),

  /**
   * Exclui serviço
   * Rota: DELETE /servicos/delete
   * @param {Object} payload - { idservicos: number }
   * @returns {Promise<any>}
   */
  deleteServico: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.delete('/servicos/delete', { data: payload });
      return response.data;
    }
  }),

  /**
   * Baixa PDF do boleto
   * Rota: GET /boletos/pdf/{codigoSolicitacao}
   * @param {string} codigoSolicitacao
   * @returns {Promise<Blob>}
   */
  downloadBoletoPDF: (codigoSolicitacao) => handleRequest({
    mockFn: () => simulateLatency(new Blob(['PDF mock'], { type: 'application/pdf' })),
    apiFn: async () => {
      const response = await api.get(`/boletos/pdf/${codigoSolicitacao}`, {
        responseType: 'blob'
      });
      return response.data;
    }
  }),

  /**
   * Envia boleto por email
   * Rota: POST /boletos/enviar_email
   * @param {Object} payload - { codigo_solicitacao, idempresa }
   * @returns {Promise<any>}
   */
  enviarBoletoEmail: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true, message: 'Email enviado com sucesso' }),
    apiFn: async () => {
      const response = await api.post('/boletos/enviar_email', payload);
      return response.data;
    }
  }),

  /**
   * Agenda boletos do cliente
   * Rota: POST /agendar/boletos
   * @param {Object} payload - { data_execucao: "YYYY-M-D HH:mm:ss", data_envio: "YYYY-M-D " }
   * @returns {Promise<any>}
   */
  agendarBoletos: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true, message: 'Boletos agendados com sucesso' }),
    apiFn: async () => {
      const response = await api.post('/agendar/boletos', payload);
      return response.data;
    }
  }),

  /**
   * Busca fatura do cliente (PDF)
   * Rota: POST /servicos/mapeamento/fatura — lógica antiga Faturas (Apresentar_tela)
   * @param {number} idempresa
   * @returns {Promise<Blob|null>} Blob do PDF ou null se não houver fatura
   */
  fetchFaturaCliente: (idempresa) => handleRequest({
    mockFn: () => simulateLatency(null),
    apiFn: async () => {
      try {
        const response = await api.post('/servicos/mapeamento/fatura', { empresa: idempresa }, { responseType: 'blob' });
        if (response.status !== 200 || !(response.data instanceof Blob)) return null;
        return response.data;
      } catch {
        return null;
      }
    }
  }),

  /**
   * Busca serviços atribuídos ao cliente (por dominio)
   * Rota: POST /servicos/mapeamento — lógica antiga Atribuidos (Apresentar_tela)
   * @param {string} dominio - dominio do cliente (Tela.filtro.dominio)
   * @returns {Promise<Array<{idservico?, valor_uni?, valor_total?, item_estoque?, categoria?, ...}>>}
   */
  /**
   * Cria serviço atribuído a empresa
   * Rota: POST /servicos_empresa/create
   * @param {Object} payload - { idempresa, idservicos, quantidade }
   * @returns {Promise<any>}
   */
  createServicoEmpresa: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true, idempresa_servico: Date.now() }),
    apiFn: async () => {
      const response = await api.post('/servicos_empresa/create', payload);
      return response.data;
    }
  }),

  /**
   * Edita serviço atribuído a empresa
   * Rota: POST /servicos_empresa/edit
   * @param {Object} payload - { idempresa_servico, idempresa, idservicos, quantidade }
   * @returns {Promise<any>}
   */
  editServicoEmpresa: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.post('/servicos_empresa/edit', payload);
      return response.data;
    }
  }),

  /**
   * Exclui serviço atribuído a empresa
   * Rota: DELETE /servicos_empresa/delete
   * @param {Object} payload - { idempresa_servico }
   * @returns {Promise<any>}
   */
  deleteServicoEmpresa: (payload) => handleRequest({
    mockFn: () => simulateLatency({ success: true }),
    apiFn: async () => {
      const response = await api.delete('/servicos_empresa/delete', { data: payload });
      return response.data;
    }
  }),

  fetchServicosMapeamentoCliente: (idempresa) => handleRequest({
    mockFn: () => simulateLatency([]),
    apiFn: async () => {
      const response = await api.post('/servicos/mapeamento', { idempresa: idempresa });
      const data = response?.data;
      const base = data?.Base_Dados_API ?? (Array.isArray(data) ? data : null);
      const first = Array.isArray(base) ? base[0] : base && typeof base === 'object' ? Object.values(base)[0] : null;
      
      if (!first) return [];

      let servicesList = [];
      
      // Nova estrutura: tipos_servico -> servicos
      if (first.tipos_servico && Array.isArray(first.tipos_servico)) {
        first.tipos_servico.forEach(group => {
          if (group.servicos && Array.isArray(group.servicos)) {
            group.servicos.forEach(svc => {
              servicesList.push({
                ...svc,
                tipo_servico: group.tipo_servico,
                idempresa: first.idempresa
              });
            });
          }
        });
      } 
      // Estrutura antiga: first.servicos
      else if (first.servicos) {
        try {
          const parsed = typeof first.servicos === 'string' ? JSON.parse(first.servicos) : first.servicos;
          const list = Array.isArray(parsed) ? parsed : (parsed && typeof parsed === 'object' ? Object.values(parsed) : []);
          servicesList = list.map((item) => ({ ...item, idempresa: first.idempresa }));
        } catch {
          servicesList = [];
        }
      }

      return servicesList;
    }
  })
};
