import axios from "axios";

import { buildCommanderHeaders, resolveCommanderBaseUrl } from "./commanderHttp";
import { normalizeBancoPontosExtratoItem } from "./bancoPontos";

export type PapelUsuario = "admin" | "parceiro";

export type MeData = {
  id: string;
  nome: string;
  email: string;
  papel: PapelUsuario;
  parceiroId: string | null;
  estaAtivo: boolean;
  unidadeId: string;
};

export type BootstrapStatusData = {
  requiresBootstrap: boolean;
  estabelecimentoId: string;
  unidade: { id: string; nome: string; estabelecimentoId: string } | null;
};

export type BootstrapInitInput = {
  estabelecimentoId: string;
  unidadeNome: string;
  adminNome: string;
  adminEmail: string;
};

export type MeuParceiroPerfilData = {
  id: string;
  nome: string;
  tipoPessoa: "fisica" | "juridica";
  cpf: string | null;
  cnpj: string | null;
  email: string;
  whatsapp: string | null;
  logoUrl: string | null;
};

export type AtualizarMeuParceiroPerfilInput = {
  nome?: string;
  cpf?: string | null;
  cnpj?: string | null;
  email?: string;
  whatsapp?: string | null;
  logoUrl?: string | null;
};

export type MeuFechamentoResumoData = {
  parceiroId: string;
  competencias: Array<{
    competenciaId: string;
    mes: number;
    ano: number;
    statusCompetencia: "em_aberto" | "concluido";
    fechamento: {
      id: string;
      status: "em_aberto" | "fechado";
      pontuacaoTotalEntregue: number;
      pontuacaoMeta: number;
      pontuacaoPaga: number;
      pontuacaoBanco: number;
      fechadoEm: string | null;
      criadoEm: string;
      atualizadoEm: string;
    } | null;
  }>;
  indicadores: {
    totalPontos: number;
    saldoFechamentos: number;
    saldoBancoPontos: number;
  };
};

export type MeuBancoPontosExtratoData = {
  parceiro: {
    parceiroId: string;
    nome: string;
    codinome: string | null;
    logoUrl: string | null;
    fotoUrl: string | null;
    saldo: number;
  };
  data: Array<{
    id: string;
    parceiroId: string;
    fechamentoId: string | null;
    tipo: "credito" | "debito";
    quantidade: number;
    descricao: string;
    criadoEm: string;
    competenciaMes: number | null;
    competenciaAno: number | null;
  }>;
  meta: {
    total: number;
    paginaAtual: number;
    totalPaginas: number;
  };
};

type MeResponse = {
  success: boolean;
  data: MeData;
};

type MeuParceiroPerfilResponse = {
  success: boolean;
  data: MeuParceiroPerfilData;
};

type MeuFechamentoResumoResponse = {
  success: boolean;
  data: MeuFechamentoResumoData;
};

type MeuBancoPontosExtratoResponse = {
  success: boolean;
  data: MeuBancoPontosExtratoData;
};

type BootstrapStatusResponse = {
  success: boolean;
  data: BootstrapStatusData;
};

type BootstrapInitResponse = {
  success: boolean;
  data: {
    unidadeId: string;
    adminId: string;
  };
};

export type ExportarMeuBancoPontosExtratoResponse = {
  buffer: ArrayBuffer;
  filename: string | null;
};

type ApiErrorShape = {
  status?: number;
  data?: {
    error?: {
      code?: string;
      message?: string;
    };
  };
  message?: string;
};

function isApiError(value: unknown): value is ApiErrorShape {
  return typeof value === "object" && value !== null;
}

class AuthMeService {
  private extractFilenameFromContentDisposition(value: string | undefined): string | null {
    if (!value) return null;
    const utf8Match = value.match(/filename\*=UTF-8''([^;]+)/i);
    if (utf8Match?.[1]) {
      try {
        return decodeURIComponent(utf8Match[1]);
      } catch {
        return utf8Match[1];
      }
    }
    const regularMatch = value.match(/filename="?([^";]+)"?/i);
    return regularMatch?.[1] ?? null;
  }

  private handleAxiosError(error: unknown, fallback: string): never {
    if (axios.isAxiosError(error)) {
      if (!error.response) {
        throw new Error(
          "Não foi possível conectar na API do Commander. Verifique VITE_API_BASE_URL_COMMANDER e se o backend está acessível.",
        );
      }
      const message =
        (error.response?.data as ApiErrorShape["data"] | undefined)?.error?.message ??
        error.message ??
        fallback;
      throw new Error(message);
    }
    throw new Error(fallback);
  }

  async getMe(usuarioEmail: string): Promise<MeData | null> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders({ omitUnidadeId: true });

    try {
      const response = await axios.get<MeResponse>(`${baseUrl}/me`, {
        params: { usuarioEmail },
        headers,
      });
      return response.data.data;
    } catch (error: unknown) {
      if (axios.isAxiosError(error)) {
        const status = error.response?.status;
        const code = (error.response?.data as ApiErrorShape["data"] | undefined)?.error?.code;
        if (status === 404 || code === "USUARIO_NAO_CADASTRADO") {
          return null;
        }
        if (!error.response) {
          throw new Error(
            "Não foi possível conectar na API do Commander. Verifique VITE_API_BASE_URL_COMMANDER e se o backend está acessível.",
          );
        }
        const message =
          (error.response?.data as ApiErrorShape["data"] | undefined)?.error?.message ?? error.message;
        throw new Error(message || "Erro ao consultar acesso do usuário.");
      }
      if (isApiError(error)) {
        const status = error.status;
        const code = error.data?.error?.code;
        if (status === 404 || code === "USUARIO_NAO_CADASTRADO") {
          return null;
        }
        const message = error.data?.error?.message ?? error.message;
        throw new Error(message || "Erro ao consultar acesso do usuário.");
      }
      throw new Error("Erro ao consultar acesso do usuário.");
    }
  }

  async getBootstrapStatus(estabelecimentoId: string): Promise<BootstrapStatusData> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders({ omitUnidadeId: true });
    const response = await axios.get<BootstrapStatusResponse>(`${baseUrl}/bootstrap-status`, {
      headers,
      params: { estabelecimentoId },
    });
    return response.data.data;
  }

  async getMeuParceiroPerfil(usuarioEmail: string): Promise<MeuParceiroPerfilData> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders();
    try {
      const response = await axios.get<MeuParceiroPerfilResponse>(`${baseUrl}/me/parceiro-perfil`, {
        headers,
        params: { usuarioEmail },
      });
      return response.data.data;
    } catch (error) {
      this.handleAxiosError(error, "Erro ao carregar perfil do parceiro.");
    }
  }

  async patchMeuParceiroPerfil(
    usuarioEmail: string,
    input: AtualizarMeuParceiroPerfilInput,
  ): Promise<MeuParceiroPerfilData> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders();
    try {
      const response = await axios.patch<MeuParceiroPerfilResponse>(`${baseUrl}/me/parceiro-perfil`, input, {
        headers,
        params: { usuarioEmail },
      });
      return response.data.data;
    } catch (error) {
      this.handleAxiosError(error, "Erro ao atualizar perfil do parceiro.");
    }
  }

  async getMeuFechamento(usuarioEmail: string, ano?: number): Promise<MeuFechamentoResumoData> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders();
    try {
      const response = await axios.get<MeuFechamentoResumoResponse>(`${baseUrl}/me/fechamentos`, {
        headers,
        params: {
          usuarioEmail,
          ano,
        },
      });
      return response.data.data;
    } catch (error) {
      this.handleAxiosError(error, "Erro ao carregar meu fechamento.");
    }
  }

  async getMeuBancoPontosExtrato(
    usuarioEmail: string,
    page: number,
    perPage: number,
  ): Promise<MeuBancoPontosExtratoData> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders();
    try {
      const response = await axios.get<MeuBancoPontosExtratoResponse>(`${baseUrl}/me/banco-pontos/extrato`, {
        headers,
        params: {
          usuarioEmail,
          page,
          perPage,
        },
      });
      const payload = response.data.data;
      return {
        ...payload,
        data: (payload.data ?? []).map((row) =>
          normalizeBancoPontosExtratoItem(row as unknown as Record<string, unknown>),
        ),
      };
    } catch (error) {
      this.handleAxiosError(error, "Erro ao carregar extrato do banco de pontos.");
    }
  }

  async exportarMeuBancoPontosExtrato(usuarioEmail: string): Promise<ExportarMeuBancoPontosExtratoResponse> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders();
    try {
      const response = await axios.get<ArrayBuffer>(`${baseUrl}/me/banco-pontos/extrato/exportar`, {
        headers,
        responseType: "arraybuffer",
        params: { usuarioEmail },
      });
      return {
        buffer: response.data,
        filename: this.extractFilenameFromContentDisposition(response.headers["content-disposition"]),
      };
    } catch (error) {
      this.handleAxiosError(error, "Erro ao exportar extrato do banco de pontos.");
    }
  }

  async bootstrapInitialize(input: BootstrapInitInput): Promise<{ unidadeId: string; adminId: string }> {
    const baseUrl = resolveCommanderBaseUrl();
    const headers = await buildCommanderHeaders({ omitUnidadeId: true });
    const response = await axios.post<BootstrapInitResponse>(`${baseUrl}/bootstrap`, input, {
      headers,
    });
    return response.data.data;
  }
}

export const authMeService = new AuthMeService();
