<?php
declare(strict_types=1);

namespace App\Repositories;

use App\Core\Database;
use PDO;
use RuntimeException;
use Throwable;

final class UpdatePackageRegistryRepository
{
    /**
     * @return array<int,array<string,mixed>>
     */
    public function latest(): array
    {
        /*
         * Requête entièrement statique.
         * Aucun fragment SQL, opérateur, colonne ou limite ne dépend
         * d'une variable ou d'une entrée utilisateur.
         */
        $statement = Database::connection()->query(
            "SELECT *
             FROM cda_update_packages
             ORDER BY importe_at DESC, id DESC
             LIMIT 60"
        );

        $rows = $statement->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $statement->closeCursor();

        return $rows;
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    public function all(): array
    {
        $statement = Database::connection()->query(
            "SELECT *
             FROM cda_update_packages
             ORDER BY importe_at DESC, id DESC"
        );

        $rows = $statement->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $statement->closeCursor();

        return $rows;
    }

    /**
     * @return array<string,mixed>|null
     */
    public function find(int $packageId): ?array
    {
        if ($packageId <= 0) {
            return null;
        }

        $statement = Database::connection()->prepare(
            "SELECT *
             FROM cda_update_packages
             WHERE id = :id
             LIMIT 1"
        );
        $statement->execute(['id' => $packageId]);

        $package = $statement->fetch(PDO::FETCH_ASSOC);
        $statement->closeCursor();

        return is_array($package) ? $package : null;
    }

    public function count(): int
    {
        return (int) Database::connection()
            ->query("SELECT COUNT(*) FROM cda_update_packages")
            ->fetchColumn();
    }

    public function activeDatabase(): string
    {
        $name = Database::connection()
            ->query("SELECT DATABASE()")
            ->fetchColumn();

        return is_string($name) && $name !== '' ? $name : 'inconnue';
    }

    /**
     * @return array{database:string,count:int,packages:array<int,array<string,mixed>>,warnings:array<int,string>}
     */
    public function snapshot(): array
    {
        $warnings = [];
        $database = 'inconnue';
        $count = 0;
        $packages = [];

        try {
            $database = $this->activeDatabase();
        } catch (Throwable $error) {
            $warnings[] = 'Nom de la base active indisponible.';
            $this->log('database', $error);
        }

        try {
            $count = $this->count();
        } catch (Throwable $error) {
            $warnings[] = 'Compteur des packages indisponible.';
            $this->log('count', $error);
        }

        try {
            $packages = $this->latest();
        } catch (Throwable $error) {
            $warnings[] = 'Lecture du registre des packages indisponible.';
            $this->log('packages', $error);
        }

        return [
            'database' => $database,
            'count' => $count,
            'packages' => $packages,
            'warnings' => array_values(array_unique($warnings)),
        ];
    }

    private function log(string $section, Throwable $error): void
    {
        $directory = BASE_PATH . '/storage/logs';
        if (!is_dir($directory)) {
            @mkdir($directory, 0770, true);
        }

        $entry = json_encode([
            'at' => gmdate('c'),
            'event' => 'package_registry.error',
            'section' => $section,
            'type' => get_class($error),
            'message' => $error->getMessage(),
            'file' => $error->getFile(),
            'line' => $error->getLine(),
        ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        if (is_string($entry)) {
            @file_put_contents(
                $directory . '/package_registry.log',
                $entry . PHP_EOL,
                FILE_APPEND | LOCK_EX
            );
        }
    }
}
