<?php
// src/Signer.php
require_once __DIR__ . '/../vendor/autoload.php';

use setasign\Fpdi\Fpdi;      // FPDI base
use setasign\Fpdi\TcpdfFpdi; // FPDI + TCPDF


class Signer {

    private PDO $db;
    private string $storagePath;
    private ?string $uploadEndpoint;

    public function __construct(object $cfg) {
        $dsn = "mysql:host={$cfg->db['host']};dbname={$cfg->db['name']};charset={$cfg->db['charset']}";
        $this->db = new PDO($dsn, $cfg->db['user'], $cfg->db['pass'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        ]);

        $this->storagePath   = $cfg->storage_path;
        $this->uploadEndpoint = $cfg->upload_endpoint ?: null;
    }

    public function signPdfWithFooter(
        string $inputPath,
        ?string $pfxPath,
        ?string $pfxPassword,
        string $labName,
        int $labId
    ): array {

        // Caso o PFX não seja enviado, usamos o do banco
        if (!$pfxPath) {
            $stmt = $this->db->prepare('SELECT file_certificado FROM labs WHERE id = ? LIMIT 1');
            $stmt->execute([$labId]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $pfxPath = $row['file_certificado'] ?? null;
        }

        // Extraindo info do certificado
        $nameOnCert = "N/A";
        $cpf = "N/A";
        $pfxData = null;

        if ($pfxPath && file_exists($pfxPath)) {
            $pfxDataRaw = file_get_contents($pfxPath);
            $certs = [];

            if (@openssl_pkcs12_read($pfxDataRaw, $certs, $pfxPassword ?? '')) {
                $pfxData = $certs;
                $certInfo = openssl_x509_parse($certs['cert']);

                $subject = $certInfo['subject'] ?? [];
                $nameOnCert = $subject['CN'] ?? 'N/A';
                $cpf = $subject['serialNumber'] ?? 'N/A';
            }
        }

        // Arquivo temporário com rodapé
        $tmpFooterPdf = sys_get_temp_dir() . "/footer_" . uniqid() . ".pdf";
        $this->addFooterToPdf($inputPath, $tmpFooterPdf, $nameOnCert, $cpf, $labName);

        // Arquivo final assinado
        $signedDir = rtrim($this->storagePath, '/\\') . "/signed";
        if (!is_dir($signedDir)) mkdir($signedDir, 0777, true);

        $signedPath = $signedDir . "/signed_" . time() . ".pdf";

        // Assinar
        $this->signPdfA1($tmpFooterPdf, $signedPath, $pfxData);

        // Registrar no banco
        $stmt = $this->db->prepare("
            INSERT INTO uploads (lab_id, user_id, original_filename, stored_filename, signed_filename, status)
            VALUES (?, NULL, ?, ?, ?, ?)
        ");

        $stmt->execute([$labId, basename($inputPath), $inputPath, $signedPath, 'signed']);

        // Envio opcional
        if ($this->uploadEndpoint) {
            $this->postFileToEndpoint($signedPath, $labId);
        }

        return [
            'signed' => $signedPath,
            'footer_tmp' => $tmpFooterPdf
        ];
    }

    /**
     * Cria um PDF com rodapé de 2 linhas
     */
    private function addFooterToPdf(
        string $input,
        string $output,
        string $nomeCert,
        string $cpf,
        string $labName
    ) {
        $pdf = new Fpdi();

        $pdf->SetAutoPageBreak(false);
        $pdf->SetMargins(0, 0, 0);

        $pageCount = $pdf->setSourceFile($input);

        for ($i = 1; $i <= $pageCount; $i++) {

            $tpl = $pdf->importPage($i);
            $size = $pdf->getTemplateSize($tpl);

            $pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
            $pdf->useTemplate($tpl);

            // Rodapé
            $pdf->SetFont('Helvetica', '', 9);
            $pdf->SetTextColor(60, 60, 60);

            $lineY = $size['height'] - 22;
            $pdf->SetDrawColor(180, 180, 180);
            $pdf->SetLineWidth(0.2);
            $pdf->Line(10, $lineY, $size['width'] - 10, $lineY);

            // Linha 1
            $pdf->SetXY(10, $size['height'] - 16);
            $pdf->Cell(0, 5, "Assinado por: $nomeCert | CPF: $cpf", 0, 0, 'C');

            // Linha 2
            $pdf->SetXY(10, $size['height'] - 10);
            $pdf->Cell(0, 5, "Laboratório: $labName | Data/Hora: " . date("d/m/Y H:i:s"), 0, 0, 'C');
        }

        $pdf->Output('F', $output);
    }

    /**
     * Assinatura digital A1 - válida no ITI
     */
    private function signPdfA1(string $input, string $output, array $pfxData) {

        if (!$pfxData) {
            copy($input, $output); // fallback sem assinatura
            return;
        }

        $pub = $pfxData['cert'];
        $priv = $pfxData['pkey'];

        $pdf = new TcpdfFpdi();
        $pdf->SetAutoPageBreak(false, 0);

        $pageCount = $pdf->setSourceFile($input);

        for ($i = 1; $i <= $pageCount; $i++) {
            $tpl = $pdf->importPage($i);
            $size = $pdf->getTemplateSize($tpl);

            $pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
            $pdf->useTemplate($tpl);
        }

        // Campo de assinatura invisível (ITI aceita)
        $pdf->setSignature(
            $pub,
            $priv,
            '',
            '',
            2,
            [
                'Name' => 'Assinatura Digital ICP-Brasil',
                'Reason' => 'Assinado Digitalmente',
                'Location' => 'Brasil',
                'ContactInfo' => ''
            ]
        );

        $pdf->Output($output, 'F');
    }

    private function postFileToEndpoint(string $filePath, int $labId) {
        if (!$this->uploadEndpoint || !file_exists($filePath)) return;

        $ch = curl_init($this->uploadEndpoint);
        $cfile = curl_file_create($filePath, 'application/pdf', basename($filePath));

        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => [
                'file' => $cfile,
                'lab_id' => $labId
            ],
            CURLOPT_RETURNTRANSFER => true
        ]);

        $res = curl_exec($ch);
        curl_close($ch);
    }
}
