<?php

declare(strict_types=1);

function ensure_data_files(): void
{
    if (!is_dir(DATA_DIR)) {
        mkdir(DATA_DIR, 0777, true);
    }

    $defaults = [
        DATA_DIR . '/allowed_emails.json' => [
            'utilizadores' => [
                'admin@pascoa.local',
                'colaborador@pascoa.local',
            ],
        ],
        DATA_DIR . '/admin_emails.json' => [
            'admins' => [
                'admin@pascoa.local',
            ],
        ],
        DATA_DIR . '/items.json' => [
            [
                'id' => generate_id(),
                'title' => 'Ovo 1',
                'description' => 'Exemplo inicial para começar a recolher votos.',
                'image' => 'imagens/Ovo_1-01.png',
                'created_at' => date('c'),
            ],
            [
                'id' => generate_id(),
                'title' => 'Ovo 2',
                'description' => 'Pode editar ou remover estes exemplos na area de administracao.',
                'image' => 'imagens/Ovo_2-01.png',
                'created_at' => date('c'),
            ],
        ],
        DATA_DIR . '/votes.json' => new stdClass(),
    ];

    foreach ($defaults as $file => $content) {
        if (!file_exists($file)) {
            save_json($file, $content);
        }
    }
}

function load_json(string $file, $fallback)
{
    if (!file_exists($file)) {
        return $fallback;
    }

    $content = file_get_contents($file);
    if ($content === false || $content === '') {
        return $fallback;
    }

    $data = json_decode($content, true);

    return json_last_error() === JSON_ERROR_NONE ? $data : $fallback;
}

function save_json(string $file, $data): void
{
    $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    file_put_contents($file, $json . PHP_EOL, LOCK_EX);
}

function normalize_email(string $email): string
{
    $email = trim(mb_strtolower($email));

    return filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : '';
}

function email_is_allowed(string $email): bool
{
    $allowed = load_json(DATA_DIR . '/allowed_emails.json', ['utilizadores' => []]);

    return in_array($email, $allowed['utilizadores'] ?? [], true);
}

function email_is_admin(string $email): bool
{
    $admins = load_json(DATA_DIR . '/admin_emails.json', ['admins' => []]);

    return in_array($email, $admins['admins'] ?? [], true);
}

function current_user_email(): ?string
{
    return isset($_SESSION['user_email']) ? (string) $_SESSION['user_email'] : null;
}

function is_logged_in(): bool
{
    return current_user_email() !== null;
}

function is_admin(): bool
{
    return !empty($_SESSION['is_admin']);
}

function require_login(): void
{
    if (!is_logged_in()) {
        redirect('index.php');
    }
}

function require_admin(): void
{
    require_login();

    if (!is_admin()) {
        redirect('vote.php');
    }
}

function redirect(string $path): void
{
    header('Location: ' . $path);
    exit;
}

function escape(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

function disable_inspect(): void
{
    echo '<script>
        document.addEventListener("contextmenu", e => e.preventDefault());
        document.onkeydown = function(e) {
            if (e.keyCode == 123 || (e.ctrlKey && e.shiftKey && (e.keyCode == 73 || e.keyCode == 74 || e.keyCode == 67)) || (e.ctrlKey && e.keyCode == 85)) {
                return false;
            }
        };
    </script>';
}

function csrf_token(): string
{
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(16));
    }

    return (string) $_SESSION['csrf_token'];
}

function verify_csrf(): void
{
    $submitted = (string) ($_POST['csrf_token'] ?? '');

    if ($submitted === '' || !hash_equals(csrf_token(), $submitted)) {
        http_response_code(403);
        exit('Pedido invalido.');
    }
}

function generate_id(): string
{
    return bin2hex(random_bytes(8));
}

function get_available_images(): array
{
    $files = glob(BASE_DIR . '/imagens/*.{png,jpg,jpeg,gif,webp}', GLOB_BRACE) ?: [];
    $images = [];

    foreach ($files as $file) {
        $relative = 'imagens/' . basename($file);
        $images[$relative] = [
            'path' => $relative,
            'label' => pathinfo($file, PATHINFO_FILENAME),
        ];
    }

    ksort($images);

    return $images;
}

function build_item_stats(array $items, array $votes): array
{
    $stats = [];

    foreach ($items as $item) {
        $distribution = [1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0];
        $sum = 0;
        $count = 0;

        foreach ($votes as $userVotes) {
            if (!isset($userVotes[$item['id']]['score'])) {
                continue;
            }

            $score = (int) $userVotes[$item['id']]['score'];

            if ($score < 1 || $score > 5) {
                continue;
            }

            $distribution[$score]++;
            $sum += $score;
            $count++;
        }

        $stats[] = [
            'id' => $item['id'],
            'title' => $item['title'],
            'image' => $item['image'],
            'count' => $count,
            'average' => $count > 0 ? $sum / $count : 0,
            'distribution' => $distribution,
        ];
    }

    usort($stats, static function (array $left, array $right): int {
        return $right['average'] <=> $left['average'];
    });

    return $stats;
}

function format_distribution(array $distribution): string
{
    $parts = [];

    foreach ($distribution as $score => $count) {
        $parts[] = $score . ': ' . $count;
    }

    return implode(' | ', $parts);
}

function find_item_title(array $items, string $itemId): ?string
{
    foreach ($items as $item) {
        if ($item['id'] === $itemId) {
            return $item['title'];
        }
    }

    return null;
}

function format_datetime(?string $value): string
{
    if ($value === null || $value === '') {
        return '-';
    }

    try {
        return (new DateTimeImmutable($value))->format('d/m/Y H:i');
    } catch (Throwable $exception) {
        return $value;
    }
}
