import { Injectable, Logger, ServiceUnavailableException } from '@nestjs/common';
import { envs } from '../config';

/** Respuesta normalizada para el ERP (independiente del shape del servicio externo). */
export interface ConsultaRucResult {
  encontrado: boolean;
  ruc: string;
  dv: number | null;
  razon_social: string | null;
  estado: string | null;
  es_contribuyente: boolean | null;
  facturador_electronico: string | null;
  /** Naturaleza para el ERP: 1 = Contribuyente, 2 = No contribuyente. */
  naturaleza_codigo: 1 | 2 | null;
  /** Fuente informativa. */
  fuente: 'DNIT' | null;
}

/**
 * Proxy interno hacia el servicio local de Consulta RUC (base local → SIFEN → PLRA).
 * El servicio no tiene auth y vive en la red interna; el ERP lo consume server-to-server
 * y expone el resultado a los usuarios autenticados. Ver docs/INTEGRACION.md del servicio.
 */
@Injectable()
export class ConsultaRucService {
  private readonly logger = new Logger(ConsultaRucService.name);
  private readonly baseUrl = envs.consultaRucUrl.replace(/\/$/, '');

  async consultar(rucInput: string): Promise<ConsultaRucResult> {
    // Normalizamos: solo la base, sin dígito verificador ni guion (lo exige el servicio).
    const ruc = String(rucInput || '').split('-')[0].replace(/\D/g, '');
    if (ruc.length < 3 || ruc.length > 9) {
      return this.vacio(ruc);
    }

    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 12_000);
    try {
      const res = await fetch(`${this.baseUrl}/api/consulta-ruc`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ ruc }),
        signal: controller.signal,
      });

      if (res.status === 404) return this.vacio(ruc);
      if (res.status === 429) {
        throw new ServiceUnavailableException('El servicio de consulta de RUC está ocupado. Reintentá en unos segundos.');
      }
      if (!res.ok) {
        const body = await res.text().catch(() => '');
        this.logger.warn(`Consulta RUC ${ruc} → HTTP ${res.status}: ${body.slice(0, 200)}`);
        // Formato inválido u otro 4xx del servicio → tratamos como "no encontrado" (no rompe el alta).
        if (res.status >= 400 && res.status < 500) return this.vacio(ruc);
        throw new ServiceUnavailableException('No se pudo consultar el RUC en este momento.');
      }

      const json = (await res.json()) as { detail?: RawDetail };
      const d = json?.detail;
      if (!d) return this.vacio(ruc);

      const esContribuyente = d.esContribuyente === true;
      return {
        encontrado: true,
        ruc: d.ruc ?? ruc,
        dv: typeof d.dv === 'number' ? d.dv : null,
        razon_social: d.razonSocial ?? null,
        estado: d.estado ?? null,
        es_contribuyente: d.esContribuyente ?? null,
        facturador_electronico: d.facturadorElectronico ?? null,
        // esContribuyente=true → Contribuyente (1); false/null (padrón PLRA) → No contribuyente (2).
        naturaleza_codigo: d.esContribuyente === null || d.esContribuyente === undefined ? null : esContribuyente ? 1 : 2,
        fuente: 'DNIT',
      };
    } catch (err) {
      if (err instanceof ServiceUnavailableException) throw err;
      const msg = err instanceof Error ? err.message : String(err);
      this.logger.warn(`Consulta RUC ${ruc} falló: ${msg}`);
      // Servicio caído / timeout / red: no encontramos, pero avisamos que fue por indisponibilidad.
      throw new ServiceUnavailableException('El servicio de consulta de RUC no está disponible.');
    } finally {
      clearTimeout(timeout);
    }
  }

  private vacio(ruc: string): ConsultaRucResult {
    return {
      encontrado: false,
      ruc,
      dv: null,
      razon_social: null,
      estado: null,
      es_contribuyente: null,
      facturador_electronico: null,
      naturaleza_codigo: null,
      fuente: null,
    };
  }
}

interface RawDetail {
  ruc?: string;
  dv?: number | null;
  naturaleza?: number;
  tipoContribuyente?: number | null;
  razonSocial?: string | null;
  estado?: string | null;
  facturadorElectronico?: string | null;
  esContribuyente?: boolean | null;
}
