<?php
declare(strict_types=1);

$composerAutoload = __DIR__ . "/../vendor/autoload.php";
if (file_exists($composerAutoload)) {
    require_once $composerAutoload;
}

function redirect(string $url): void
{
    header("Location: {$url}");
    exit;
}

function setFlash(string $type, string $message): void
{
    $_SESSION["flash"] = ["type" => $type, "message" => $message];
}

function getFlash(): ?array
{
    if (!isset($_SESSION["flash"])) {
        return null;
    }
    $flash = $_SESSION["flash"];
    unset($_SESSION["flash"]);
    return $flash;
}

function normalize(string $value): string
{
    return trim($value);
}

function ensureUtf8(string $value): string
{
    $value = trim($value);
    if ($value === '') {
        return $value;
    }

    if (function_exists('mb_check_encoding') && mb_check_encoding($value, 'UTF-8')) {
        return $value;
    }

    $candidates = ['Windows-1252', 'ISO-8859-1'];
    foreach ($candidates as $from) {
        if (function_exists('mb_convert_encoding')) {
            $converted = @mb_convert_encoding($value, 'UTF-8', $from);
        } else {
            $converted = @iconv($from, 'UTF-8//IGNORE', $value);
        }
        if (is_string($converted) && $converted !== '') {
            if (!function_exists('mb_check_encoding') || mb_check_encoding($converted, 'UTF-8')) {
                return $converted;
            }
        }
    }

    return $value;
}

function sanitizeFileName(string $value): string
{
    $value = preg_replace('/[^\p{L}\p{N}\s._-]+/u', '', $value);
    $value = trim($value);
    $value = preg_replace('/[\s\t\n\r]+/', '-', $value);
    $value = preg_replace('/-+/', '-', $value);
    return $value === '' ? 'attestation' : $value;
}

function sanitizeDirectoryName(string $value, int $maxLength = 80): string
{
    $value = sanitizeFileName($value);
    if ($value === '') {
        return 'module';
    }

    if (mb_strlen($value) > $maxLength) {
        $hash = substr(sha1($value), 0, 8);
        $value = mb_substr($value, 0, $maxLength - 9) . '-' . $hash;
    }

    return $value;
}

function pdfCreateDocument(string $html, string $title = 'document', string $paper = 'A4', string $orientation = 'portrait'): string
{
    if (class_exists('Dompdf\\Dompdf')) {
        $options = new \Dompdf\Options();
        $options->set('isHtml5ParserEnabled', true);
        $options->set('isRemoteEnabled', true);
        $options->set('defaultFont', 'DejaVu Sans');
        $dompdf = new \Dompdf\Dompdf($options);
        $dompdf->loadHtml($html);
        $dompdf->setPaper($paper, $orientation);
        $dompdf->render();
        return $dompdf->output();
    }

    if (class_exists('TCPDF')) {
        $pdf = new TCPDF();
        $pdf->SetCreator(PDF_CREATOR);
        $pdf->SetAuthor('PIS');
        $pdf->SetTitle($title);
        $pdf->SetMargins(15, 15, 15);
        $pdf->AddPage(strtoupper(substr($orientation, 0, 1)));
        $pdf->writeHTML($html, true, false, true, false, '');
        return $pdf->output('', 'S');
    }

    throw new RuntimeException('Aucune bibliothèque PDF installée. Installez Dompdf ou TCPDF pour générer des PDF.');
}

function readSpreadsheetRows(string $filePath, string $extension): array
{
    if ($extension === "csv") {
        return readCsvRows($filePath);
    }
    if ($extension === "xlsx") {
        return readXlsxRows($filePath);
    }
    return [];
}

function getPage(): int
{
    $page = (int) ($_GET["page"] ?? 1);
    return max(1, $page);
}

function paginate(int $total, int $perPage): array
{
    $page = getPage();
    $totalPages = max(1, (int) ceil($total / $perPage));
    if ($page > $totalPages) {
        $page = $totalPages;
    }
    $offset = ($page - 1) * $perPage;
    return [
        "page" => $page,
        "perPage" => $perPage,
        "total" => $total,
        "totalPages" => $totalPages,
        "offset" => $offset,
    ];
}

function renderPagination(int $page, int $totalPages, string $basePath, array $extra = []): string
{
    if ($totalPages <= 1) {
        return "";
    }
    $html = '<div class="pagination">';
    for ($i = 1; $i <= $totalPages; $i++) {
        $query = array_merge($extra, ["page" => $i]);
        $url = $basePath . "?" . http_build_query($query);
        $class = $i === $page ? "active" : "";
        $html .= '<a class="' . $class . '" href="' . htmlspecialchars($url) . '">' . $i . '</a>';
    }
    $html .= "</div>";
    return $html;
}

function exportCsv(string $filename, array $header, array $rows): void
{
    header("Content-Type: text/csv; charset=UTF-8");
    header("Content-Disposition: attachment; filename=\"{$filename}\"");
    echo "\xEF\xBB\xBF";
    $out = fopen("php://output", "w");
    fputcsv($out, $header, ";");
    foreach ($rows as $row) {
        fputcsv($out, $row, ";");
    }
    fclose($out);
    exit;
}

function readCsvRows(string $filePath): array
{
    $rows = [];
    if (($handle = fopen($filePath, "r")) === false) {
        return $rows;
    }
    $firstLine = fgets($handle);
    if ($firstLine === false) {
        fclose($handle);
        return $rows;
    }
    $delimiter = substr_count($firstLine, ";") > substr_count($firstLine, ",") ? ";" : ",";
    rewind($handle);
    while (($data = fgetcsv($handle, 0, $delimiter)) !== false) {
        $data = array_map(
            static fn ($v): string => ensureUtf8(trim((string) $v)),
            $data
        );
        if (!empty(array_filter($data, static fn ($v) => trim((string) $v) !== ""))) {
            $rows[] = $data;
        }
    }
    fclose($handle);
    return $rows;
}

function readXlsxRows(string $filePath): array
{
    $zip = new ZipArchive();
    if ($zip->open($filePath) !== true) {
        return [];
    }

    $sharedStrings = [];
    $sharedXml = $zip->getFromName("xl/sharedStrings.xml");
    if ($sharedXml !== false) {
        $xml = @simplexml_load_string($sharedXml);
        if ($xml !== false && isset($xml->si)) {
            foreach ($xml->si as $si) {
                if (isset($si->t)) {
                    $sharedStrings[] = (string) $si->t;
                    continue;
                }
                $text = "";
                foreach ($si->r as $run) {
                    $text .= (string) $run->t;
                }
                $sharedStrings[] = $text;
            }
        }
    }

    $sheetXml = $zip->getFromName("xl/worksheets/sheet1.xml");
    $zip->close();
    if ($sheetXml === false) {
        return [];
    }

    $xml = @simplexml_load_string($sheetXml);
    if ($xml === false || !isset($xml->sheetData->row)) {
        return [];
    }

    $rows = [];
    foreach ($xml->sheetData->row as $row) {
        $cells = [];
        $maxIndex = -1;
        foreach ($row->c as $cell) {
            $cellRef = (string) ($cell["r"] ?? "");
            $columnRef = preg_replace("/\\d+/", "", $cellRef);
            $columnIndex = $columnRef !== "" ? columnLettersToIndex($columnRef) : ($maxIndex + 1);

            $value = "";
            $type = (string) ($cell["t"] ?? "");
            if ($type === "inlineStr") {
                $value = (string) ($cell->is->t ?? "");
            } else {
                $rawValue = (string) ($cell->v ?? "");
                if ($type === "s") {
                    $index = (int) $rawValue;
                    $value = $sharedStrings[$index] ?? "";
                } else {
                    $value = $rawValue;
                }
            }

            $cells[$columnIndex] = trim($value);
            if ($columnIndex > $maxIndex) {
                $maxIndex = $columnIndex;
            }
        }

        if ($maxIndex >= 0) {
            $normalized = [];
            for ($i = 0; $i <= $maxIndex; $i++) {
                $normalized[] = $cells[$i] ?? "";
            }
            $cells = $normalized;
        }

        if (!empty(array_filter($cells, static fn ($v) => $v !== ""))) {
            $rows[] = $cells;
        }
    }
    return $rows;
}

function columnLettersToIndex(string $letters): int
{
    $letters = strtoupper($letters);
    $index = 0;
    $length = strlen($letters);
    for ($i = 0; $i < $length; $i++) {
        $index = ($index * 26) + (ord($letters[$i]) - 64);
    }
    return $index - 1;
}
