<?php

namespace App\Helpers\Support;

class TaxCertificateHelper
{
    /**
     *  Convierte bytes DER de un certificado a PEM.
     *
     *  @param  string  $derBytes   Contenido del Certificado en Binario
     *
     *  @return string Certificado en formato PEM
     */

    public static function derToPemCertificate(string $derBytes): string
    {
        $b64 = chunk_split(base64_encode($derBytes), 64, "\n");
        return "-----BEGIN CERTIFICATE-----\n{$b64}-----END CERTIFICATE-----\n";
    }

    /**
     *  Parsea un certificado PEM con openssl_x509_parse.
     *
     *  @param  string  $cerPem   Contenido del Certificado en formato PEM
     *
     *  @return array Claves del certificado como 'serialNumberHex','validFrom_time_t','validTo_time_t', etc., o null si falla.
     */
    public static function parseCertificate(string $cerPem): ?array
    {
        $parsed = @openssl_x509_parse($cerPem, false);
        if (!$parsed || !isset($parsed['validFrom_time_t'], $parsed['validTo_time_t'])) {
            return null;
        }

        // Normaliza serial en hex (algunos devuelven decimal)
        if (isset($parsed['serialNumberHex'])) {
            $serialHex = strtoupper($parsed['serialNumberHex']);
        } else {
            // serialNumber decimal → hex
            $serialHex = isset($parsed['serialNumber']) ? strtoupper(dechex((int) $parsed['serialNumber'])) : null;
        }
        $parsed['serialNumberHex'] = $serialHex;

        return $parsed;
    }

    /**
     * Revierte la Encriptación hexadecimal aplicada sobre el certificado CDS almacenado.
     * Pudiendo revertir todo el contenido o solo ciertas porciones del mismo
     *
     *  @param string $hex Valor a revertir (Hexadecimal -> Decimal)
     *
     *  @return string Cadena en Decimal desencriptada
     */
    public static function revertHex(string $hex): string
    {
        $hex = strtolower($hex);
        $dec = '0';
        $len = strlen($hex);

        for ($i = 0; $i < $len; $i++) {
            $current = hexdec($hex[$i]);
            $dec = bcmul($dec, '16');
            $dec = bcadd($dec, (string) $current);
        }

        return $dec;
    }

    /**
     *  Convierte el número de serie de un certificado (en HEX) al número de certificado del SAT (noCertificado).
     *
     *  @param  string       $serialHex  Número de serie del certificado en hexadecimal.
     *
     *  @return string|null  Número de certificado del SAT (usualmente 20 dígitos) o null si el valor es inválido o no cumple el formato esperado.
     */
    public static function serialHexToSatCertificateNumber(string $serialHex): ?string
    {
        $trimmed_text = preg_replace('/[^0-9A-Fa-f]/', '', $serialHex);
            if ($trimmed_text === '' || strlen($trimmed_text) % 2 !== 0) return null; // serie corrupta o incompleta

        $binary_text = hex2bin($trimmed_text);
            if ($binary_text === false) return null;

        $certificate_number = trim($binary_text);
            if (!preg_match('/^\d+$/', $certificate_number)) return null;

        // if (strlen($certificate_number) !== 20) {}

        return $certificate_number;
    }


    public static function isCsd(array $meta): bool
    {
        $subject = $meta['subject'] ?? [];
        $ou = $subject['OU'] ?? ($subject['organizationalUnitName'] ?? null);

        if ($ou && str_contains(strtoupper($ou), 'SELLO DIGITAL')) {
            return true;
        }

        return false;
    }
}
