<?php
// +-------------------------------------------------+
// © 2002-2004 PMB Services / www.sigb.net pmb@sigb.net et contributeurs (voir www.sigb.net)
// +-------------------------------------------------+
// $Id: CheckSignatures.php,v 1.1.2.2 2026/02/02 12:50:12 rtigero Exp $

namespace Pmb\Digitalsignature\Library;

use explnum;
use Pmb\Digitalsignature\Models\DocnumCertifiedFields;
use Pmb\Digitalsignature\Models\DocnumCertifier;
use Pmb\Digitalsignature\Models\SignatureModel;
use upload_folder;

class CheckSignatures
{
    protected $uploadFolderId = 0;

    protected $signedDocnumsIds = array();

    // protected $apiSignature = null;

    // protected $signatures = array();

    protected $errors = array();

    protected $nbSignaturesVerified = 0;

    protected $signature = null;

    public function __construct()
    {
        $this->fetchUploadFolderId();
        $this->fetchSignedDocnums();
    }

    /**
     * Vérification de l'intégrité des signatures de documents numériques
     *
     * @return void
     */
    public function checkSignatures(int $signature_id = 0): void
    {
        /*foreach ($this->signatures as $signature) {
            $this->checkSignature($signature["id"]);
        }*/
        global $msg;

        if ($signature_id != 0) {
            $this->signature = new SignatureModel($signature_id);
            //$this->signature->fetchAllFields();
        }

        foreach ($this->signedDocnumsIds as $docnumId) {
            $entity = new explnum($docnumId);
            $certifier = new DocnumCertifier($entity);
            $cmsPath = $certifier->getCmsFilePath();
            //$check = $this->apiSignature->checkSignature($entity, $cmsPath);
            $check = $certifier->check();
            if (false === $check["check"]) {
                //La signature n'est plus valide
                $this->errors[] = [
                    'docnumId' => $docnumId,
                    'name' => $cmsPath,
                    'error' => $msg["check_sign_invalid_signature"]
                ];
            } else if ($this->signature instanceof SignatureModel) {
                $this->checkSignatureMetadata($entity, $check["data"]);
            }
            $this->nbSignaturesVerified++;
        }

        $this->signature = null;
    }

    /**
     * Parcourt récursivement le répertoire pour trouver tous les documents numériques signés
     *
     * @return void
     */
    protected function fetchSignedDocnums(): void
    {
        $uploadFolder = new upload_folder($this->uploadFolderId);
        $path = $uploadFolder->repertoire_path;

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($path)
        );

        foreach ($iterator as $file) {
            if ($file->getExtension() === 'cms') {
                $explodedName = explode("_", $file->getFilename());
                $this->signedDocnumsIds[] = intval(str_replace(".cms", "", $explodedName[count($explodedName) - 1]));
            }
        }
    }

    /*protected function fetchSignatures(): void
    {
        $this->signatures = SignatureModel::getSignatureList();
    }

    protected function checkSignature(int $signatureId): void
    {
        $signatureModel = new SignatureModel($signatureId);
        $certificate = $signatureModel->getCertificate();

        switch ($certificate->mode) {
            case CertificateModel::CERTIFICATE_MODE_API:
                $this->apiSignature = new ApiSignature($certificate->url, $certificate->token);
                $this->checkApiSignature($signatureId);
                break;
            case CertificateModel::CERTIFICATE_MODE_LOCAL:
                break;
            default:
                break;
        }
    }*/

    /*protected function checkApiSignature(int $signatureId): void
    {
        $this->fetchSignedDocnums();

        foreach ($this->signedDocnumsIds as $docnumId) {
            $entity = new explnum($docnumId);
            $certifier = new DocnumCertifier($entity);
            $cmsPath = $certifier->getCmsFilePath();
            $check = $this->apiSignature->checkSignature($entity, $cmsPath);
            if (false === $check) {
                //La signature n'est plus valide
                $this->errors[] = [
                    'docnumId' => $docnumId,
                    'name' => $entity->explnum_rep_path . $entity->explnum_nomfichier,
                    'error' => 'Signature invalide'
                ];
            }
            var_dump($check);
        }
    }*/

    /**
     * Récupère l'identifiant du répertoire d'upload contenant les signatures
     *
     * @return void
     */
    protected function fetchUploadFolderId(): void
    {
        global $pmb_digital_signature_folder_id;

        $this->uploadFolderId = $pmb_digital_signature_folder_id;

        $plugins = \plugins::get_instance();
        if (isset($plugins->get_plugins()["digital_signature"])) {
            $conf = new \digital_signature_conf();
            if (! empty($conf->get_conf_input_directory())) {
                $this->uploadFolderId = intval($conf->get_conf_input_directory());
            }
        }
    }

    /**
     * Vérification des métadonnées présentes dans la signature
     *
     * @param explnum $entity
     * @param array $check
     * @return void
     */
    protected function checkSignatureMetadata(explnum $entity, array $check): void
    {
        global $msg;

        $dcf = new DocnumCertifiedFields();
        $dcf->setRecordId($entity->explnum_notice);
        $dcf->setDocnumId($entity->explnum_id);

        $data = json_decode($dcf->getFields($this->signature->fields));

        foreach ($data as $property => $value) {
            if (! array_key_exists($property, $check)) {
                // La propriété n'existe pas dans le check
                $this->errors[] = [
                    'docnumId' => $entity->explnum_id,
                    'name' => $entity->explnum_rep_path . $entity->explnum_nomfichier,
                    'error' => sprintf($msg["check_sign_missing_property"], $property)
                ];
                continue;
            }
            // Vérifier que la valeur correspond
            if ($value !== $check[$property]) {
                $this->errors[] = [
                    'docnumId' => $entity->explnum_id,
                    'name' => $entity->explnum_rep_path . $entity->explnum_nomfichier,
                    'error' => sprintf($msg["check_sign_invalid_value"], $property)
                ];
            }
        }

        foreach ($check as $property => $value) {
            if (! in_array($property, array("extra", "meta")) && ! isset($data->$property)) {
                // La propriété n'existe pas dans la signature
                $this->errors[] = [
                    'docnumId' => $entity->explnum_id,
                    'name' => $entity->explnum_rep_path . $entity->explnum_nomfichier,
                    'error' => sprintf($msg["check_sign_missing_setting"], $property)
                ];
            }
        }
    }

    /**
     * Indique si des erreurs ont été détectées lors du check
     *
     * @return bool
     */
    public function hasErrors(): bool
    {
        return count($this->errors) > 0;
    }

    /**
     * Retourne le tableau des erreurs
     *
     * @return array
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Retourne le nombre de signatures vérifiées
     *
     * @return int
     */
    public function getNbSignaturesVerified(): int
    {
        return $this->nbSignaturesVerified;
    }
}
