<?php

require_once __DIR__ . '/config.php';

function auth_config_value(array $environment_keys, array $constant_keys = []): ?string
{
    foreach ($environment_keys as $environment_key) {
        $value = getenv($environment_key);
        if ($value !== false) {
            $value = trim((string) $value);
            if ($value !== '') {
                return $value;
            }
        }
    }

    foreach ($constant_keys as $constant_key) {
        if (defined($constant_key)) {
            $value = trim((string) constant($constant_key));
            if ($value !== '') {
                return $value;
            }
        }
    }

    return null;
}

function auth_start_session(): void
{
    if (session_status() !== PHP_SESSION_ACTIVE) {
        session_start();
    }
}

function auth_bootstrap(): void
{
    static $auth_bootstrap_done = false;

    if ($auth_bootstrap_done) {
        return;
    }

    $pdo = db();
    $pdo->exec(
        "CREATE TABLE IF NOT EXISTS tbl_auth (
            cl_auth_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
            cl_auth_user VARCHAR(190) NOT NULL UNIQUE,
            cl_auth_pass VARCHAR(255) NOT NULL,
            cl_auth_right ENUM('admin', 'moderator', 'member') NOT NULL DEFAULT 'member'
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
    );

    $pdo->exec(
        "CREATE TABLE IF NOT EXISTS tbl_page_access (
            cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
            cl_page_key VARCHAR(190) NOT NULL UNIQUE,
            cl_page_file VARCHAR(190) NOT NULL UNIQUE,
            cl_page_label VARCHAR(190) NOT NULL,
            cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1,
            cl_allow_moderator TINYINT(1) NOT NULL DEFAULT 0,
            cl_allow_member TINYINT(1) NOT NULL DEFAULT 0,
            cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"
    );

    $stmt_auth_role_column = $pdo->query("SHOW COLUMNS FROM tbl_auth LIKE 'cl_auth_right'");
    $auth_role_column = $stmt_auth_role_column->fetch();
    $auth_role_type = strtolower((string) ($auth_role_column['Type'] ?? ''));
    if (strpos($auth_role_type, "'moderator'") === false) {
        $pdo->exec("ALTER TABLE tbl_auth MODIFY cl_auth_right ENUM('admin', 'moderator', 'member') NOT NULL DEFAULT 'member'");
    }

    $stmt_page_access_columns = $pdo->query('SHOW COLUMNS FROM tbl_page_access');
    $page_access_columns = [];
    foreach ($stmt_page_access_columns->fetchAll() as $page_access_column) {
        $page_access_columns[] = (string) ($page_access_column['Field'] ?? '');
    }

    if (!in_array('cl_allow_moderator', $page_access_columns, true)) {
        $pdo->exec('ALTER TABLE tbl_page_access ADD COLUMN cl_allow_moderator TINYINT(1) NOT NULL DEFAULT 0 AFTER cl_allow_admin');
        $pdo->exec('UPDATE tbl_page_access SET cl_allow_moderator = cl_allow_member');
    }

    $sql_count_admin = "SELECT COUNT(*) FROM tbl_auth WHERE cl_auth_right = 'admin'";
    $stmt_count_admin = $pdo->query($sql_count_admin);
    $cl_auth_admin_total = (int) $stmt_count_admin->fetchColumn();

    if ($cl_auth_admin_total === 0) {
        [$cl_auth_user, $plain_default_password] = auth_default_admin_credentials();

        if ($cl_auth_user === '' || $plain_default_password === '') {
            throw new RuntimeException(
                "Aucun administrateur n'existe et aucun couple DEFAULT_ADMIN_USER / DEFAULT_ADMIN_PASSWORD n'est configuré."
            );
        }

        $cl_auth_pass = password_hash($plain_default_password, PASSWORD_DEFAULT);
        $cl_auth_right = 'admin';

        $stmt_insert_admin = $pdo->prepare(
            'INSERT INTO tbl_auth (cl_auth_user, cl_auth_pass, cl_auth_right) VALUES (:cl_auth_user, :cl_auth_pass, :cl_auth_right)'
        );
        $stmt_insert_admin->execute([
            'cl_auth_user' => $cl_auth_user,
            'cl_auth_pass' => $cl_auth_pass,
            'cl_auth_right' => $cl_auth_right,
        ]);
    }

    $auth_bootstrap_done = true;
}

function auth_default_admin_credentials(): array
{
    $cl_auth_user = auth_config_value(
        ['DEFAULT_ADMIN_USER', 'APP_DEFAULT_ADMIN_USER'],
        ['DEFAULT_ADMIN_USER', 'APP_DEFAULT_ADMIN_USER']
    ) ?? 'admin';

    $plain_default_password = auth_config_value(
        ['DEFAULT_ADMIN_PASSWORD', 'APP_DEFAULT_ADMIN_PASSWORD'],
        ['DEFAULT_ADMIN_PASSWORD', 'APP_DEFAULT_ADMIN_PASSWORD']
    );

    if ($plain_default_password === null) {
        return ['', ''];
    }

    return [$cl_auth_user, $plain_default_password];
}

function auth_csrf_token(): string
{
    auth_start_session();

    if (empty($_SESSION['csrf_token']) || !is_string($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['csrf_token'];
}

function auth_validate_csrf(?string $csrf_token): bool
{
    auth_start_session();

    if (!isset($_SESSION['csrf_token']) || !is_string($_SESSION['csrf_token'])) {
        return false;
    }

    if ($csrf_token === null) {
        return false;
    }

    return hash_equals($_SESSION['csrf_token'], $csrf_token);
}

function auth_is_logged_in(): bool
{
    auth_start_session();

    return isset($_SESSION['user']) && isset($_SESSION['role']);
}

function auth_is_admin(): bool
{
    return auth_current_role() === 'admin';
}

function auth_is_moderator(): bool
{
    return auth_current_role() === 'moderator';
}

function auth_valid_roles(): array
{
    return ['admin', 'moderator', 'member'];
}

function auth_role_label(string $role): string
{
    static $labels = [
        'admin' => 'Administrateur',
        'moderator' => 'Modérateur',
        'member' => 'Membre',
    ];

    return $labels[$role] ?? ucfirst($role);
}

function auth_current_user(): string
{
    auth_start_session();

    return isset($_SESSION['user']) ? (string) $_SESSION['user'] : '';
}

function auth_current_role(): string
{
    auth_start_session();

    return isset($_SESSION['role']) ? (string) $_SESSION['role'] : '';
}

function auth_flash_set(string $flash_type, string $flash_message): void
{
    auth_start_session();
    $_SESSION['flash'] = [
        'type' => $flash_type,
        'message' => $flash_message,
    ];
}

function auth_flash_get(): ?array
{
    auth_start_session();

    if (!isset($_SESSION['flash']) || !is_array($_SESSION['flash'])) {
        return null;
    }

    $flash = $_SESSION['flash'];
    unset($_SESSION['flash']);

    return $flash;
}

function auth_page_basename(string $page_file): string
{
    $basename = basename(trim($page_file));

    if ($basename === '' || preg_match('/^[a-zA-Z0-9._-]+$/', $basename) !== 1) {
        throw new InvalidArgumentException('Nom de page invalide.');
    }

    return $basename;
}

function auth_page_default_member_access(string $page_file): int
{
    static $member_defaults = [
        'scnotification.php' => 1,
        'scpreset.php' => 1,
    ];

    $page_file = auth_page_basename($page_file);

    return $member_defaults[$page_file] ?? 0;
}

function auth_page_default_moderator_access(string $page_file): int
{
    return auth_page_default_member_access($page_file);
}

function auth_page_access_defaults(string $page_file, string $page_label = ''): array
{
    $normalized_page_file = auth_page_basename($page_file);
    $normalized_page_label = trim($page_label) !== '' ? trim($page_label) : $normalized_page_file;

    return [
        'cl_page_key' => pathinfo($normalized_page_file, PATHINFO_FILENAME),
        'cl_page_file' => $normalized_page_file,
        'cl_page_label' => $normalized_page_label,
        'cl_allow_admin' => 1,
        'cl_allow_moderator' => auth_page_default_moderator_access($normalized_page_file),
        'cl_allow_member' => auth_page_default_member_access($normalized_page_file),
    ];
}

function auth_page_access_ensure(string $page_file, string $page_label = ''): array
{
    auth_bootstrap();

    $defaults = auth_page_access_defaults($page_file, $page_label);
    $pdo = db();

    $stmt = $pdo->prepare(
        'SELECT cl_page_access_id, cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_moderator, cl_allow_member
         FROM tbl_page_access
         WHERE cl_page_file = :cl_page_file
         LIMIT 1'
    );
    $stmt->execute([
        'cl_page_file' => $defaults['cl_page_file'],
    ]);
    $row = $stmt->fetch();

    if (!$row) {
        $stmt_insert = $pdo->prepare(
            'INSERT INTO tbl_page_access (cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_moderator, cl_allow_member)
             VALUES (:cl_page_key, :cl_page_file, :cl_page_label, :cl_allow_admin, :cl_allow_moderator, :cl_allow_member)'
        );
        $stmt_insert->execute($defaults);

        $stmt->execute([
            'cl_page_file' => $defaults['cl_page_file'],
        ]);
        $row = $stmt->fetch();
    } elseif ($defaults['cl_page_label'] !== '' && (string) $row['cl_page_label'] !== $defaults['cl_page_label']) {
        $stmt_update_label = $pdo->prepare(
            'UPDATE tbl_page_access SET cl_page_label = :cl_page_label WHERE cl_page_file = :cl_page_file'
        );
        $stmt_update_label->execute([
            'cl_page_label' => $defaults['cl_page_label'],
            'cl_page_file' => $defaults['cl_page_file'],
        ]);
        $row['cl_page_label'] = $defaults['cl_page_label'];
    }

    if (!$row) {
        throw new RuntimeException('Impossible d\'initialiser la configuration d\'accès de la page.');
    }

    $row['cl_allow_admin'] = (int) ($row['cl_allow_admin'] ?? 1);
    $row['cl_allow_moderator'] = (int) ($row['cl_allow_moderator'] ?? 0);
    $row['cl_allow_member'] = (int) ($row['cl_allow_member'] ?? 0);

    return $row;
}

function auth_user_can_access_page(string $page_file, string $page_label = ''): bool
{
    auth_start_session();
    auth_bootstrap();

    if (!auth_is_logged_in()) {
        return false;
    }

    $role = auth_current_role();

    if ($role === 'admin') {
        return true;
    }

    $row = auth_page_access_ensure($page_file, $page_label);

    if ($role === 'moderator') {
        return (int) $row['cl_allow_moderator'] === 1;
    }

    if ($role === 'member') {
        return (int) $row['cl_allow_member'] === 1;
    }

    return false;
}

function auth_require_page_access(string $page_file, string $page_label = ''): void
{
    if (!auth_is_logged_in()) {
        header('Location: index.php');
        exit;
    }

    if (auth_is_admin()) {
        auth_page_access_ensure($page_file, $page_label);
        return;
    }

    if (auth_user_can_access_page($page_file, $page_label)) {
        return;
    }

    auth_flash_set('error', 'Accès refusé : cette page n\'est pas ouverte pour votre niveau d\'autorisation.');
    header('Location: index.php');
    exit;
}

function auth_handle_page_access_post(string $page_file, string $page_label = ''): void
{
    auth_start_session();
    auth_bootstrap();

    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
        return;
    }

    if (!isset($_POST['page_access_action'])) {
        return;
    }

    $redirect_target = auth_page_basename($page_file);

    if (!auth_is_admin()) {
        auth_flash_set('error', 'Seul un administrateur peut modifier les accès de page.');
        header('Location: index.php');
        exit;
    }

    $csrf_token = isset($_POST['csrf_token']) ? (string) $_POST['csrf_token'] : null;
    if (!auth_validate_csrf($csrf_token)) {
        auth_flash_set('error', 'Jeton CSRF invalide.');
        header('Location: ' . $redirect_target);
        exit;
    }

    $row = auth_page_access_ensure($page_file, $page_label);
    $cl_allow_moderator = isset($_POST['cl_allow_moderator']) ? 1 : 0;
    $cl_allow_member = isset($_POST['cl_allow_member']) ? 1 : 0;

    $stmt = db()->prepare(
        'UPDATE tbl_page_access
         SET cl_page_label = :cl_page_label,
             cl_allow_admin = 1,
             cl_allow_moderator = :cl_allow_moderator,
             cl_allow_member = :cl_allow_member
         WHERE cl_page_file = :cl_page_file'
    );
    $stmt->execute([
        'cl_page_label' => $row['cl_page_label'],
        'cl_allow_moderator' => $cl_allow_moderator,
        'cl_allow_member' => $cl_allow_member,
        'cl_page_file' => $row['cl_page_file'],
    ]);

    auth_flash_set('success', 'Accès mis à jour pour ' . $row['cl_page_label'] . '.');
    header('Location: ' . $redirect_target);
    exit;
}

function auth_render_page_access_widget(string $page_file, string $page_label = ''): string
{
    if (!auth_is_admin()) {
        return '';
    }

    $row = auth_page_access_ensure($page_file, $page_label);
    $csrf_token = auth_csrf_token();
    $action = htmlspecialchars($row['cl_page_file'], ENT_QUOTES, 'UTF-8');
    $label = htmlspecialchars((string) $row['cl_page_label'], ENT_QUOTES, 'UTF-8');
    $csrf = htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8');
    $moderator_checked = (int) $row['cl_allow_moderator'] === 1 ? 'checked' : '';
    $member_checked = (int) $row['cl_allow_member'] === 1 ? 'checked' : '';

    return <<<HTML
<div style="position:fixed;top:10px;right:10px;z-index:9999;background:rgba(10,14,18,0.94);border:1px solid rgba(162,155,120,0.45);border-radius:12px;padding:10px 12px;box-shadow:0 10px 24px rgba(0,0,0,0.35);backdrop-filter:blur(8px);font-family:Arial,sans-serif;color:#f2f2f2;min-width:220px;max-width:min(92vw,280px);">
    <form method="post" action="{$action}" style="margin:0;display:flex;flex-direction:column;gap:8px;">
        <input type="hidden" name="csrf_token" value="{$csrf}">
        <input type="hidden" name="page_access_action" value="save">
        <div style="font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:#a29b78;">Accès page</div>
        <div style="font-size:14px;font-weight:700;line-height:1.25;">{$label}</div>
        <label style="display:flex;align-items:center;gap:8px;font-size:13px;opacity:.9;">
            <input type="checkbox" checked disabled>
            <span>Admin <small style="opacity:.7;">(toujours autorisé)</small></span>
        </label>
        <label style="display:flex;align-items:center;gap:8px;font-size:13px;">
            <input type="checkbox" name="cl_allow_moderator" value="1" {$moderator_checked}>
            <span>Modérateur</span>
        </label>
        <label style="display:flex;align-items:center;gap:8px;font-size:13px;">
            <input type="checkbox" name="cl_allow_member" value="1" {$member_checked}>
            <span>Membre</span>
        </label>
        <button type="submit" style="appearance:none;border:0;border-radius:8px;padding:8px 10px;background:#a29b78;color:#111;font-weight:700;cursor:pointer;">Appliquer</button>
    </form>
</div>
HTML;
}

function auth_navigation_items(): array
{
    return [
        ['file' => 'admin.php', 'label' => 'Utilisateurs', 'admin_only' => true],
        ['file' => 'scwebhook.php', 'label' => 'WEBHOOK'],
        ['file' => 'scnotification.php', 'label' => 'NOTIF DISCORD'],
        ['file' => 'scitems.php', 'label' => 'Base d\'Objets'],
        ['file' => 'scstatsitem.php', 'label' => 'Stats Item'],
        ['file' => 'scitemcustom.php', 'label' => 'Objets perso.'],
        ['file' => 'sccharacters.php', 'label' => 'Personnages'],
        ['file' => 'scmining.php', 'label' => 'Scanner Minage'],
        ['file' => 'scmanufactures.php', 'label' => 'Manufactures'],
        ['file' => 'scvaisseaux.php', 'label' => 'Vaisseaux'],
        ['file' => 'scpreset.php', 'label' => 'Presets Vaisseau'],
    ];
}

function auth_render_app_nav(string $current_page): string
{
    if (!auth_is_logged_in()) {
        return '';
    }

    $current_page = auth_page_basename($current_page);
    $html = '<nav class="nav-tabs">';

    foreach (auth_navigation_items() as $item) {
        $file = (string) $item['file'];
        $label = (string) $item['label'];
        $admin_only = !empty($item['admin_only']);

        if ($admin_only && !auth_is_admin()) {
            continue;
        }

        if (!auth_is_admin() && !auth_user_can_access_page($file, $label)) {
            continue;
        }

        $is_active = $file === $current_page ? ' class="active"' : '';
        $html .= '<a href="' . htmlspecialchars($file, ENT_QUOTES, 'UTF-8') . '"' . $is_active . '>' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '</a>';
    }

    $html .= '</nav>';

    return $html;
}
