import * as forge from 'node-forge';

interface ParsedP12Certificate {
    certificate: forge.pki.Certificate;
    privateKey: forge.pki.PrivateKey;
    issuerName: string;
    serialNumber: string;
    certificateX509: string;
    base64Der: string;
    publicKey: {
        modulus: string;
        exponent: string;
    };
}

interface SignatureIdentifiersInterface {
    signatureNumber: string;
    certificateNumber: string;
    signedInfoNumber: string;
    signedPropertiesNumber: string;
    signedPropertiesIdNumber: string;
    signatureValueNumber: string;
    referenceIdNumber: string;
    ObjectNumber: string;
}

interface SignXmlRequest {
    p12Buffer: Uint8Array;
    password: string;
    xmlBuffer: Uint8Array;
}

interface XadesBesResultInterface {
    xadesBes: string;
}

declare function signXml(cmd: SignXmlRequest): Promise<string>;

declare enum CodigoPais {
    AMERICAN_SAMOA = "016",
    BOUVET_ISLAND = "074",
    ARGENTINA = "101",
    BOLIVIA = "102",
    BRASIL = "103",
    CANAD = "104",
    COLOMBIA = "105",
    COSTA_RICA = "106",
    CUBA = "107",
    CHILE = "108",
    ANGUILA = "109",
    ESTADOS_UNIDOS = "110",
    GUATEMALA = "111",
    HAIT = "112",
    HONDURAS = "113",
    JAMAICA = "114",
    MALVINAS_ISLAS = "115",
    MXICO = "116",
    NICARAGUA = "117",
    PANAM = "118",
    PARAGUAY = "119",
    PER = "120",
    PUERTO_RICO = "121",
    REPBLICA_DOMINICANA = "122",
    EL_SALVADOR = "123",
    TRINIDAD_Y_TOBAGO = "124",
    URUGUAY = "125",
    VENEZUELA = "126",
    CURAZAO = "127",
    BAHAMAS = "129",
    BARBADOS = "130",
    GRANADA = "131",
    GUYANA = "132",
    SURINAM = "133",
    ANTIGUA_Y_BARBUDA = "134",
    BELICE = "135",
    DOMINICA = "136",
    SAN_CRISTOBAL_Y_NEVIS = "137",
    SANTA_LUCA = "138",
    SAN_VICENTE_Y_LAS_GRANAD = "139",
    ANTILLAS_HOLANDESAS = "140",
    ARUBA = "141",
    BERMUDA = "142",
    GUADALUPE = "143",
    GUYANA_FRANCESA = "144",
    ISLAS_CAIMN = "145",
    ISLAS_VIRGENES_BRITANICAS = "146",
    JOHNSTON_ISLA = "147",
    MARTINICA = "148",
    MONTSERRAT_ISLA = "149",
    TURCAS_Y_CAICOS_ISLAS = "151",
    VIRGENES_ISLAS_NORTAMER = "152",
    ALBANIA = "201",
    ALEMANIA = "202",
    AUSTRIA = "203",
    BLGICA = "204",
    BULGARIA = "205",
    ALBORAN_Y_PEREJIL = "207",
    DINAMARCA = "208",
    ESPAA = "209",
    FRANCIA = "211",
    FINLANDIA = "212",
    REINO_UNIDO = "213",
    GRECIA = "214",
    PAISES_BAJOS_HOLANDA = "215",
    HUNGRA = "216",
    IRLANDA = "217",
    ISLANDIA = "218",
    ITALIA = "219",
    LUXEMBURGO = "220",
    MALTA = "221",
    NORUEGA = "222",
    POLONIA = "223",
    PORTUGAL = "224",
    RUMANIA = "225",
    SUECIA = "226",
    SUIZA = "227",
    CANARIAS_ISLAS = "228",
    UCRANIA = "229",
    RUSIA = "230",
    YUGOSLAVIA = "231",
    ANDORRA = "233",
    LIECHTENSTEIN = "234",
    MNACO = "235",
    SAN_MARINO = "237",
    VATICANO_SANTA_SEDE = "238",
    GIBRALTAR = "239",
    BELARUS = "241",
    BOSNIA_Y_HERZEGOVINA = "242",
    CROACIA = "243",
    ESLOVENIA = "244",
    ESTONIA = "245",
    GEORGIA = "246",
    GROENLANDIA = "247",
    LETONIA = "248",
    LITUANIA = "249",
    MOLDOVA = "250",
    MACEDONIA = "251",
    ESLOVAQUIA = "252",
    ISLAS_FAROE = "253",
    FRENCH_SOUTHERN_TERRITORIES = "260",
    AFGANISTAN = "301",
    ARABIA_SAUDITA = "302",
    MYANMAR_BURMA = "303",
    CAMBOYA = "304",
    COREA_NORTE = "306",
    TAIWAN_CHINA = "307",
    FILIPINAS = "308",
    INDIA = "309",
    INDONESIA = "310",
    IRAK = "311",
    IRN_REPBLICA_ISLMICA = "312",
    ISRAEL = "313",
    JAPN = "314",
    JORDANIA = "315",
    KUWAIT = "316",
    LAOS_REP_POP_DEMOC = "317",
    LIBANO = "318",
    MALASIA = "319",
    MONGOLIA_MANCHURIA = "321",
    PAKISTN = "322",
    SIRIA = "323",
    TAILANDIA = "325",
    BAHREIN = "327",
    BANGLADESH = "328",
    BUTN = "329",
    COREA_DEL_SUR = "330",
    CHINA_POPULAR = "331",
    CHIPRE = "332",
    EMIRATOS_ARABES_UNIDOS = "333"
}

/**
 * Códigos de retención (IVA & Renta) según tablas oficiales
 */
declare enum CODIGO_RETENCION_ENUM {
    /**
     * 100% (aplica para retenciones de IVA de conformidad con Resolución No. NAC-DGERCGC21-00000063)
     * Tarifa en el XML: 1
     */
    IVA_CIENTO_POR_CIENTO_RESOLUCION = 3,
    /**
     * 12% (Retención de IVA presuntivo por Editores a Margen de Comercialización/Vocedores)
     * Tarifa en el XML: 0.12
     */
    IVA_DOCE_POR_CIENTO_PRESUNTIVO_EDITORES = 4,
    /**
     * 100% (Retención de IVA venta periódicos y/o revistas a Distribuidores)
     * Tarifa en el XML: 100
     */
    IVA_CIENTO_POR_CIENTO_DISTRIBUIDORES = 5,
    /**
     * 100% (Retención de IVA venta de periódicos y/o revistas a voceadores)
     * Tarifa en el XML: 100
     */
    IVA_CIENTO_POR_CIENTO_VOCEADORES = 6,
    /**
     * 0.002 (2 por mil)
     * Tarifa en el XML: 0.20
     */
    RENTA_DOS_POR_MIL = 327,
    /**
     * 0.003 (3 por mil)
     * Tarifa en el XML: 0.20
     */
    RENTA_TRES_POR_MIL = 328
}

declare enum CONTRIBUYENTE_RIMPE_ENUM {
    RIMPE_GENERAL = "CONTRIBUYENTE R\u00C9GIMEN RIMPE",
    RIMPE_POPULAR = "CONTRIBUYENTE NEGOCIO POPULAR - R\u00C9GIMEN RIMPE"
}

declare enum ENV_ENUM {
    TEST = 1,
    PROD = 2
}

declare enum IDENTIFICATION_CODE_ENUM {
    RUC = "04",
    CEDULA = "05",
    PASAPORTE = "06",
    CONSUMIDOR_FINAL = "07",
    EXTERIOR = "08"
}

declare enum IMPUESTO_A_RETENER_ENUM {
    IVA_PRESUNTIVO_Y_RENTA = 4
}

declare enum IVA_PERCENTAGE_CODE_ENUM {
    IVA_0 = "0",// 0%
    IVA_12 = "2",// 12%
    IVA_14 = "3",// 14%
    IVA_15 = "4",// 15%
    IVA_5 = "5",// 5%
    NO_OBJETO_IVA = "6",// No objeto de impuesto
    EXENTO_IVA = "7",// Exento de IVA
    IVA_DIFERENCIADO = "8",// IVA diferenciado
    IVA_13 = "10"
}

declare enum OBLIGADO_CONTABILIDAD_ENUM {
    SI = "SI",
    NO = "NO"
}

declare enum PAYMENT_METHOD_CODE_ENUM {
    SIN_UTILIZACION_DEL_SISTEMA_FINANCIERO = "01",
    COMPENSACION_DE_DEUDAS = "15",
    TARJETA_DE_DEBITO = "16",
    DINERO_ELECTRONICO = "17",
    TARJETA_PREPAGO = "18",
    TARJETA_DE_CREDITO = "19",
    OTROS_CON_SISTEMA_FINANCIERO = "20",
    ENDOSO_DE_TITULOS = "21"
}

declare enum TAX_CODE_ENUM {
    VAT = 2,// IVA
    ICE = 3,// Impuesto a los Consumos Especiales
    IRBPNR = 5
}

declare class InfoTributariaModel {
    ambiente: ENV_ENUM;
    razonSocial: string;
    nombreComercial?: string;
    ruc: string;
    estab: string;
    ptoEmi: string;
    secuencial: string;
    dirMatriz: string;
    agenteRetencion?: string;
    contribuyenteRimpe?: CONTRIBUYENTE_RIMPE_ENUM;
}
declare class TotalImpuestoModel {
    codigo: TAX_CODE_ENUM;
    codigoPorcentaje: number;
    baseImponible: number;
    valor: number;
    descuentoAdicional?: number;
}
declare class TotalConImpuestosModel {
    totalImpuesto: TotalImpuestoModel[];
}
declare class PagoModel {
    formaPago: PAYMENT_METHOD_CODE_ENUM;
    total: number;
    plazo?: number;
    unidadTiempo?: string;
}
declare class PagosModel {
    pago: PagoModel[];
}
declare class InfoFacturaModel {
    fechaEmision: Date;
    dirEstablecimiento: string;
    contribuyenteEspecial?: string;
    obligadoContabilidad?: OBLIGADO_CONTABILIDAD_ENUM;
    tipoIdentificacionComprador: IDENTIFICATION_CODE_ENUM;
    guiaRemision?: string;
    razonSocialComprador: string;
    identificacionComprador: string;
    direccionComprador?: string;
    totalSinImpuestos: number;
    totalDescuento: number;
    totalConImpuestos: TotalConImpuestosModel;
    propina: number;
    importeTotal: number;
    moneda?: string;
    pagos: PagosModel;
    valorRetIva?: number;
    valorRetRenta?: number;
}
declare class DetAdicionalModel {
    nombre: string;
    valor: string;
}
declare class ImpuestoDetalleModel {
    codigo: TAX_CODE_ENUM;
    codigoPorcentaje: number;
    tarifa: number;
    baseImponible: number;
    valor: number;
}
declare class DetallesAdicionalesModel {
    detAdicional: DetAdicionalModel[];
}
declare class ImpuestosModel {
    impuesto: ImpuestoDetalleModel[];
}
declare class DetalleModel {
    codigoPrincipal: string;
    codigoAuxiliar?: string;
    descripcion: string;
    cantidad: number;
    precioUnitario: number;
    descuento: number;
    precioTotalSinImpuesto: number;
    detallesAdicionales?: DetallesAdicionalesModel;
    impuestos: ImpuestosModel;
}
declare class CampoAdicionalModel {
    nombre: string;
    value: string;
}
declare class InfoAdicionalModel {
    campoAdicional: CampoAdicionalModel[];
}
declare class DetallesModel {
    detalle: DetalleModel[];
}
declare class RetencionesModel {
    retencion: RetencionModel[];
}
declare class RetencionModel {
    codigo: IMPUESTO_A_RETENER_ENUM;
    codigoPorcentaje: CODIGO_RETENCION_ENUM;
    tarifa: number;
    valor: number;
}
declare class ComprobanteModel {
    infoTributaria: InfoTributariaModel;
    infoFactura: InfoFacturaModel;
    detalles: DetallesModel;
    retenciones?: RetencionesModel;
    infoAdicional?: InfoAdicionalModel;
    /**
     * Anexo 26: RUC del proveedor del sistema o servicio de facturacion
     * electronica. Se agrega automaticamente a infoAdicional como
     * <campoAdicional nombre="RUC Proveedor">.
     */
    rucProveedor?: string;
}

interface InvoiceSriBuilder {
    factura: FacturaInfo;
}
interface FacturaInfo {
    $: {
        id: string;
        version: string;
    };
    infoTributaria: InfoTributaria;
    infoFactura: InfoFactura;
    detalles: Detalles;
    retenciones: Retenciones;
    infoAdicional: InfoAdicional;
}
declare class Retenciones {
    retencion: Retencion[];
}
declare class Retencion {
    codigo: IMPUESTO_A_RETENER_ENUM;
    codigoPorcentaje: CODIGO_RETENCION_ENUM;
    tarifa: string;
    valor: string;
}
interface InfoTributaria {
    ambiente: number;
    tipoEmision: string;
    razonSocial: string;
    nombreComercial: string;
    ruc: string;
    claveAcceso: string;
    codDoc: string;
    estab: string;
    ptoEmi: string;
    secuencial: string;
    dirMatriz: string;
    contribuyenteRimpe?: string;
    agenteRetencion?: string;
}
interface InfoFactura {
    fechaEmision: string;
    dirEstablecimiento: string;
    contribuyenteEspecial?: string;
    obligadoContabilidad?: "SI" | "NO";
    comercioExterior?: string;
    incoTermFactura?: string;
    lugarIncoTerm?: string;
    paisOrigen?: string;
    puertoEmbarque?: string;
    puertoDestino?: string;
    paisDestino?: string;
    paisAdquisicion?: string;
    tipoIdentificacionComprador: string;
    guiaRemision?: string;
    razonSocialComprador: string;
    identificacionComprador: string;
    direccionComprador: string;
    totalSinImpuestos: string;
    incoTermTotalSinImpuestos?: string;
    totalDescuento: string;
    totalConImpuestos: {
        totalImpuesto: TotalImpuesto[];
    };
    propina: string;
    fleteInternacional?: number;
    seguroInternacional?: number;
    gastosAduaneros?: number;
    gastosTransporteOtros?: number;
    importeTotal: string;
    moneda: string;
    pagos: {
        pago: Pago[];
    };
    valorRetIva?: string;
    valorRetRenta?: string;
}
interface TotalImpuesto {
    codigo: TAX_CODE_ENUM;
    codigoPorcentaje: string;
    baseImponible: string;
    valor: string;
    descuentoAdicional?: string;
}
interface Detalles {
    detalle: Detalle[];
}
interface Pago {
    formaPago: string;
    total: string;
    plazo: number;
    unidadTiempo: string;
}
interface Detalle {
    codigoPrincipal: string;
    codigoAuxiliar: string;
    descripcion: string;
    cantidad: string;
    precioUnitario: string;
    descuento: string;
    precioTotalSinImpuesto: string;
    detallesAdicionales?: {
        detAdicional: DetAdicional[];
    };
    impuestos: {
        impuesto: ImpuestoDetalle[];
    };
}
interface DetAdicional {
    $: {
        nombre: string;
        valor: string;
    };
}
interface ImpuestoDetalle {
    codigo: TAX_CODE_ENUM;
    codigoPorcentaje: string;
    tarifa: string;
    baseImponible: string;
    valor: string;
}
interface InfoAdicional {
    campoAdicional: CampoAdicional[];
}
interface CampoAdicional {
    $: {
        nombre: string;
    };
    _: string;
}

interface ResponseGenerateXmlModel {
    invoiceJson: InvoiceSriBuilder;
    generatedXml: string;
}

type ComprobanteType = InstanceType<typeof ComprobanteModel>;

declare function generateXmlInvoice(invoice: ComprobanteType): Promise<ResponseGenerateXmlModel>;

declare const SRI_URLS: {
    readonly test: {
        readonly recepcion: "https://celcer.sri.gob.ec/comprobantes-electronicos-ws/RecepcionComprobantesOffline?wsdl";
        readonly autorizacion: "https://celcer.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantesOffline?wsdl";
    };
    readonly prod: {
        readonly recepcion: "https://cel.sri.gob.ec/comprobantes-electronicos-ws/RecepcionComprobantesOffline?wsdl";
        readonly autorizacion: "https://cel.sri.gob.ec/comprobantes-electronicos-ws/AutorizacionComprobantesOffline?wsdl";
    };
};
type SRIEnv = keyof typeof SRI_URLS;

interface AuthorizeXmlCommand {
    claveAcceso: string;
    env: SRIEnv;
}

interface SriAuthorizationMessage {
    identificador: string;
    mensaje: string;
    tipo: string;
    informacionAdicional?: string;
}
interface SriAuthorizationResponse {
    claveAcceso: string;
    estadoAutorizacion: string;
    comprobante: string;
    rucEmisor: string;
    fechaAutorizacion: string;
    ambiente: string;
    comprobanteCrudo: string;
    mensajes: SriAuthorizationMessage[] | null;
}

interface ValidateXmlCommand {
    xml: Uint8Array;
    env: SRIEnv;
}

interface ValidateXmlResponse {
    estado: string;
    mensaje?: string;
}

declare function authorizeXml(data: AuthorizeXmlCommand): Promise<SriAuthorizationResponse>;

declare function validateXml(data: ValidateXmlCommand): Promise<ValidateXmlResponse>;

declare class InfrastructureError extends Error {
    constructor(message: string);
}
declare class UnknownSignStrategyError extends InfrastructureError {
    constructor(friendlyName: string);
}
declare class SignStrategyError extends InfrastructureError {
    constructor(message: string);
}
declare class SigningKeyNotFoundError extends SignStrategyError {
    constructor(friendlyName: string);
}
declare class PrivateKeyExtractionError extends SignStrategyError {
    constructor(sourceLabel?: string);
}
declare class UanatacaCertificateNotFoundError extends SignStrategyError {
    constructor();
}
declare class InvalidP12StructureError extends Error {
    constructor();
}
declare class InvalidP12PasswordError extends Error {
    constructor();
}
declare class InvalidXmlStructureError extends Error {
    constructor(message?: string);
}

type ErrorCode = "UANATACA_CERT_NOT_FOUND" | "SIGNING_KEY_NOT_FOUND" | "PRIVATE_KEY_EXTRACTION_ERROR" | "UNKNOWN_SIGN_STRATEGY" | "SIGN_STRATEGY_ERROR" | "INFRASTRUCTURE_ERROR" | "UNHANDLED_ERROR" | "UNKNOWN_ERROR" | "P12_PASSWORD_ERROR" | "P12_STRUCTURE_ERROR" | "XML_STRUCTURE_ERROR";

interface HandledError {
    code: ErrorCode;
    message: string;
    original: Error;
}
/**
 * Forma del error que lanza `signXml`: el error original enriquecido con el
 * codigo que permite discriminarlo sin comparar el texto del mensaje.
 */
interface SignXmlError extends Error {
    code: ErrorCode;
}

declare class ValidationException extends Error {
    readonly errors: string[];
    constructor(errors: string[]);
}

declare abstract class BaseSRIError extends Error {
    readonly estado: string;
    readonly identificador: string;
    readonly mensajeSRI: string;
    readonly informacionAdicional: string;
    readonly tipo: string;
    readonly claveAcceso: string;
    constructor(params: {
        estado: string;
        identificador: string;
        mensaje: string;
        informacionAdicional: string;
        tipo: string;
        claveAcceso: string;
        customMessage?: string;
    });
}
declare class SRIError extends Error {
    constructor(message: string);
}

declare class SRIAutorizacionError extends Error {
    readonly estado: string;
    readonly identificador: string;
    readonly mensajeSRI: string;
    readonly informacionAdicional: string;
    readonly tipo: string;
    readonly claveAcceso: string;
    readonly ambiente?: string;
    readonly comprobanteXml?: string;
    constructor(params: {
        estado: string;
        identificador: string;
        mensaje: string;
        informacionAdicional: string;
        tipo: string;
        claveAcceso: string;
        ambiente?: string;
        comprobanteXml?: string;
    });
}
declare class SRIUnauthorizedError extends SRIError {
    readonly estado: string;
    constructor(estado: string);
}

declare class SRIRejectedError extends BaseSRIError {
    constructor(params: {
        estado: string;
        identificador: string;
        mensaje: string;
        informacionAdicional: string;
        tipo: string;
        claveAcceso: string;
    });
}

export { type AuthorizeXmlCommand, BaseSRIError, CODIGO_RETENCION_ENUM, CONTRIBUYENTE_RIMPE_ENUM, type CampoAdicional, CampoAdicionalModel, CodigoPais, ComprobanteModel, type ComprobanteType, type DetAdicional, DetAdicionalModel, type Detalle, DetalleModel, type Detalles, DetallesAdicionalesModel, DetallesModel, ENV_ENUM, type ErrorCode, type FacturaInfo, type HandledError, IDENTIFICATION_CODE_ENUM, IMPUESTO_A_RETENER_ENUM, IVA_PERCENTAGE_CODE_ENUM, type ImpuestoDetalle, ImpuestoDetalleModel, ImpuestosModel, type InfoAdicional, InfoAdicionalModel, type InfoFactura, InfoFacturaModel, type InfoTributaria, InfoTributariaModel, InfrastructureError, InvalidP12PasswordError, InvalidP12StructureError, InvalidXmlStructureError, type InvoiceSriBuilder, OBLIGADO_CONTABILIDAD_ENUM, PAYMENT_METHOD_CODE_ENUM, type Pago, PagoModel, PagosModel, type ParsedP12Certificate, PrivateKeyExtractionError, type ResponseGenerateXmlModel, Retencion, RetencionModel, Retenciones, RetencionesModel, SRIAutorizacionError, type SRIEnv, SRIError, SRIRejectedError, SRIUnauthorizedError, SRI_URLS, SignStrategyError, type SignXmlError, type SignXmlRequest, type SignatureIdentifiersInterface, SigningKeyNotFoundError, type SriAuthorizationMessage, type SriAuthorizationResponse, TAX_CODE_ENUM, TotalConImpuestosModel, type TotalImpuesto, TotalImpuestoModel, UanatacaCertificateNotFoundError, UnknownSignStrategyError, type ValidateXmlCommand, type ValidateXmlResponse, ValidationException, type XadesBesResultInterface, authorizeXml, generateXmlInvoice, signXml, validateXml };
