import axios, { AxiosRequestConfig } from 'axios';
import https from 'https';
import fs from 'fs';

export interface Endpoint {
  route: string;
  method: string;
}

export interface HttpClientOptions {
  baseUrl: string;
  endpoint: Endpoint;
  body?: any;
  params?: Record<string, any>;
  headers?: Record<string, string>;
  routeParams?: Record<string, string | number>;
  // Certificado
  certificate?: string; // Caminho do arquivo ou base64
  pemKey?: string; // Caminho do arquivo ou base64
  cert_base64?: boolean;
  partner_token?: string;
  validateMtls?: boolean;
  authorization?: string; // Bearer token
  idempotencyKey?: string;
}

function buildAgent(options: HttpClientOptions): https.Agent | undefined {
  if (!options.certificate) return undefined;
  try {
    if (!options.cert_base64) {
      if (options.pemKey) {
        return new https.Agent({
          cert: fs.readFileSync(options.certificate),
          key: fs.readFileSync(options.pemKey),
          passphrase: '',
        });
      } else {
        return new https.Agent({
          pfx: fs.readFileSync(options.certificate),
          passphrase: '',
        });
      }
    } else {
      if (options.pemKey) {
        return new https.Agent({
          cert: Buffer.from(options.certificate, 'base64'),
          key: Buffer.from(options.pemKey, 'base64'),
          passphrase: '',
        });
      } else {
        return new https.Agent({
          pfx: Buffer.from(options.certificate, 'base64'),
          passphrase: '',
        });
      }
    }
  } catch (error) {
    throw new Error('Erro ao ler o certificado ou chave: ' + (error as Error).message);
  }
}

function buildRoute(route: string, routeParams?: Record<string, string | number>): string {
  if (!routeParams) return route;
  return route.replace(/:([a-zA-Z0-9_]+)/g, (_, key) => {
    if (routeParams[key] === undefined) throw new Error(`Parâmetro de rota ausente: ${key}`);
    return encodeURIComponent(String(routeParams[key]));
  });
}

export async function httpRequest<T = any>(options: HttpClientOptions): Promise<T> {
  const {
    baseUrl,
    endpoint,
    body,
    params,
    headers = {},
    routeParams,
    certificate,
    pemKey,
    cert_base64,
    partner_token,
    validateMtls,
    authorization,
    idempotencyKey,
  } = options;

  const url = baseUrl + buildRoute(endpoint.route, routeParams);
  const agent = buildAgent(options);

  // Monta headers padrões
  const defaultHeaders: Record<string, string> = {
    ...(authorization ? { Authorization: authorization } : {}),
    ...(validateMtls !== undefined ? { 'x-skip-mtls-checking': (!validateMtls).toString() } : {}),
    ...(partner_token ? { 'partner-token': partner_token } : {}),
    ...(idempotencyKey ? { 'x-idempotency-key': idempotencyKey } : {}),
  };

  const config: AxiosRequestConfig = {
    url,
    method: endpoint.method as any,
    data: body,
    params,
    headers: { ...defaultHeaders, ...headers },
    ...(agent ? { httpsAgent: agent } : {}),
  };

  try {
    const response = await axios(config);
    return response.data;
  } catch (error: any) {
    if (error.response && error.response.data) {
      throw error.response.data;
    }
    throw error;
  }
} 