<?php

declare(strict_types=1);

class AdminUsersController
{
    private PDO $db;

    public function __construct()
    {
        $this->db = $this->pdo();
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start();
        }
    }

    private function pdo(): PDO
    {
        if (class_exists('Database')) {
            $d = Database::getInstance();

            foreach (['getConnection', 'connect', 'connection', 'pdo'] as $m) {
                if (method_exists($d, $m)) {
                    $pdo = $d->$m();
                    if ($pdo instanceof PDO) {
                        return $pdo;
                    }
                }
            }
        }

        if (defined('DB_HOST')) {
            return new PDO(
                'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
                DB_USER,
                DB_PASS,
                [
                    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                ]
            );
        }

        $config = [];
        $configFile = dirname(__DIR__, 2) . '/config/database.php';
        if (is_file($configFile)) {
            $config = require $configFile;
        }

        $host = $config['host'] ?? 'localhost';
        $name = $config['database'] ?? 'shquier_easyconf';
        $user = $config['username'] ?? 'shquier_admin';
        $pass = $config['password'] ?? 'K@reem2030';

        return new PDO(
            "mysql:host={$host};dbname={$name};charset=utf8mb4",
            $user,
            $pass,
            [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]
        );
    }

    private function requireSuperAdmin(): void
    {
        $role = strtolower((string)($_SESSION['role'] ?? $_SESSION['user_role'] ?? ''));
        $roleId = (int)($_SESSION['role_id'] ?? 0);

        if ($role !== 'super_admin' && $role !== 'superadmin' && $roleId !== 1) {
            http_response_code(403);
            exit('Access denied.');
        }
    }

    private function csrf(): string
    {
        if (empty($_SESSION['_csrf_admin_users'])) {
            $_SESSION['_csrf_admin_users'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['_csrf_admin_users'];
    }

    private function checkCsrf(): void
    {
        $token = (string)($_POST['_csrf'] ?? '');
        if ($token === '' || !hash_equals((string)($_SESSION['_csrf_admin_users'] ?? ''), $token)) {
            http_response_code(419);
            exit('Invalid security token.');
        }
    }

    private function tableExists(string $table): bool
    {
        $st = $this->db->prepare("SHOW TABLES LIKE ?");
        $st->execute([$table]);
        return (bool)$st->fetchColumn();
    }

    private function columns(string $table): array
    {
        static $cache = [];
        if (isset($cache[$table])) {
            return $cache[$table];
        }

        if (!$this->tableExists($table)) {
            return $cache[$table] = [];
        }

        $rows = $this->db->query("DESCRIBE `$table`")->fetchAll();
        return $cache[$table] = array_map(static fn($r) => $r['Field'], $rows);
    }

    private function hasCol(string $table, string $col): bool
    {
        return in_array($col, $this->columns($table), true);
    }

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

    private function flash(string $type, string $message): void
    {
        $_SESSION['flash_admin_users'] = ['type' => $type, 'message' => $message];
    }

    public function index(): void
    {
        $this->requireSuperAdmin();

        $conferenceId = (int)($_GET['conference_id'] ?? ($_SESSION['current_conference_id'] ?? $_SESSION['conference_id'] ?? 0));
        $q = trim((string)($_GET['q'] ?? ''));
        $roleFilter = trim((string)($_GET['role'] ?? ''));
        $page = max(1, (int)($_GET['page'] ?? 1));
        $perPage = (int)($_GET['per_page'] ?? 25);
        if (!in_array($perPage, [10, 25, 50, 100], true)) {
            $perPage = 25;
        }
        $offset = ($page - 1) * $perPage;

        $conferences = [];
        if ($this->tableExists('conferences')) {
            $nameCol = $this->hasCol('conferences', 'name') ? 'name' : ($this->hasCol('conferences', 'title') ? 'title' : 'id');
            $conferences = $this->db->query("SELECT id, `$nameCol` AS name FROM conferences ORDER BY id DESC")->fetchAll();
        }

        if ($conferenceId <= 0 && !empty($conferences)) {
            $conferenceId = (int)$conferences[0]['id'];
        }

        $roles = [];
        if ($this->tableExists('roles')) {
            $roles = $this->db->query("SELECT id, name FROM roles ORDER BY name")->fetchAll();
        }

        $where = [];
        $params = [];

        if ($conferenceId > 0 && $this->tableExists('user_conferences')) {
            $where[] = "EXISTS (
                SELECT 1 FROM user_conferences uc
                WHERE uc.user_id = u.id
                AND uc.conference_id = :conference_id
            )";
            $params[':conference_id'] = $conferenceId;
        } elseif ($conferenceId > 0 && $this->tableExists('conference_user_roles')) {
            $where[] = "EXISTS (
                SELECT 1 FROM conference_user_roles curx
                WHERE curx.user_id = u.id
                AND curx.conference_id = :conference_id
            )";
            $params[':conference_id'] = $conferenceId;
        }

        if ($q !== '') {
            $parts = [];
            foreach (['name', 'full_name', 'first_name', 'last_name', 'email', 'username'] as $c) {
                if ($this->hasCol('users', $c)) {
                    $parts[] = "u.`$c` LIKE :q";
                }
            }
            if ($parts) {
                $where[] = '(' . implode(' OR ', $parts) . ')';
                $params[':q'] = '%' . $q . '%';
            }
        }

        if ($roleFilter !== '') {
            if ($this->tableExists('roles') && $this->tableExists('conference_user_roles')) {
                $where[] = "EXISTS (
                    SELECT 1
                    FROM conference_user_roles cfr
                    JOIN roles rr ON rr.id = cfr.role_id
                    WHERE cfr.user_id = u.id
                    " . ($conferenceId > 0 ? "AND cfr.conference_id = :role_conference_id" : "") . "
                    AND rr.name = :role_filter
                )";
                $params[':role_filter'] = $roleFilter;
                if ($conferenceId > 0) {
                    $params[':role_conference_id'] = $conferenceId;
                }
            }
        }

        $whereSql = $where ? ('WHERE ' . implode(' AND ', $where)) : '';

        $nameExpr = "COALESCE(NULLIF(u.name,''), NULLIF(u.full_name,''), TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))), u.username, u.email)";
        if (!$this->hasCol('users', 'name') && !$this->hasCol('users', 'full_name')) {
            $nameExpr = "COALESCE(TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))), u.username, u.email)";
        }

        $emailExpr = $this->hasCol('users', 'email') ? "u.email" : "''";
        $usernameExpr = $this->hasCol('users', 'username') ? "u.username" : "''";
        $statusExpr = $this->hasCol('users', 'status') ? "u.status" : "''";
        $createdExpr = $this->hasCol('users', 'created_at') ? "u.created_at" : "NULL";

        $roleSub = "''";
        if ($this->tableExists('conference_user_roles') && $this->tableExists('roles')) {
            $roleSub = "(SELECT GROUP_CONCAT(DISTINCT r.name ORDER BY r.name SEPARATOR ', ')
                         FROM conference_user_roles cur
                         JOIN roles r ON r.id = cur.role_id
                         WHERE cur.user_id = u.id " . ($conferenceId > 0 ? "AND cur.conference_id = " . (int)$conferenceId : "") . ")";
        }

        $countSql = "SELECT COUNT(*) FROM users u $whereSql";
        $countSt = $this->db->prepare($countSql);
        foreach ($params as $k => $v) {
            $countSt->bindValue($k, $v);
        }
        $countSt->execute();
        $total = (int)$countSt->fetchColumn();
        $pages = max(1, (int)ceil($total / $perPage));

        $sql = "
            SELECT
                u.id,
                $nameExpr AS display_name,
                $emailExpr AS email,
                $usernameExpr AS username,
                $statusExpr AS status,
                $createdExpr AS created_at,
                COALESCE($roleSub, '') AS conference_roles
            FROM users u
            $whereSql
            ORDER BY u.id DESC
            LIMIT :limit OFFSET :offset
        ";

        $st = $this->db->prepare($sql);
        foreach ($params as $k => $v) {
            $st->bindValue($k, $v);
        }
        $st->bindValue(':limit', $perPage, PDO::PARAM_INT);
        $st->bindValue(':offset', $offset, PDO::PARAM_INT);
        $st->execute();
        $users = $st->fetchAll();

        $flash = $_SESSION['flash_admin_users'] ?? null;
        unset($_SESSION['flash_admin_users']);

        $csrf = $this->csrf();

        $view = dirname(__DIR__) . '/views/admin/users/index.php';
        if (!is_file($view)) {
            exit('Missing view: ' . $view);
        }

        require $view;
    }

    public function update(): void
    {
        $this->requireSuperAdmin();
        $this->checkCsrf();

        $id = (int)($_POST['id'] ?? 0);
        if ($id <= 0) {
            $this->flash('danger', 'Invalid user.');
            $this->redirect('/easychair/admin/users');
        }

        $sets = [];
        $params = [':id' => $id];

        $map = [
            'name' => 'name',
            'full_name' => 'full_name',
            'first_name' => 'first_name',
            'last_name' => 'last_name',
            'email' => 'email',
            'username' => 'username',
            'status' => 'status',
        ];

        foreach ($map as $post => $col) {
            if ($this->hasCol('users', $col) && array_key_exists($post, $_POST)) {
                $sets[] = "`$col` = :$col";
                $params[":$col"] = trim((string)$_POST[$post]);
            }
        }

        if (!$sets) {
            $this->flash('warning', 'No editable columns found.');
            $this->redirect('/easychair/admin/users?' . http_build_query([
                'conference_id' => $_POST['conference_id'] ?? '',
                'q' => $_POST['q'] ?? '',
                'page' => $_POST['page'] ?? 1,
            ]));
        }

        $sql = "UPDATE users SET " . implode(', ', $sets) . " WHERE id = :id";
        $st = $this->db->prepare($sql);
        $st->execute($params);

        $this->flash('success', 'User updated successfully.');
        $this->redirect('/easychair/admin/users?' . http_build_query([
            'conference_id' => $_POST['conference_id'] ?? '',
            'q' => $_POST['q'] ?? '',
            'role' => $_POST['role'] ?? '',
            'page' => $_POST['page'] ?? 1,
        ]));
    }

    public function resetPassword(): void
    {
        $this->requireSuperAdmin();
        $this->checkCsrf();

        $id = (int)($_POST['id'] ?? 0);
        $password = (string)($_POST['password'] ?? '');

        if ($id <= 0 || strlen($password) < 8) {
            $this->flash('danger', 'Password must be at least 8 characters.');
            $this->redirect('/easychair/admin/users');
        }

        $passwordCol = $this->hasCol('users', 'password') ? 'password' : ($this->hasCol('users', 'password_hash') ? 'password_hash' : '');
        if ($passwordCol === '') {
            $this->flash('danger', 'No password column found.');
            $this->redirect('/easychair/admin/users');
        }

        $hash = password_hash($password, PASSWORD_DEFAULT);

        $st = $this->db->prepare("UPDATE users SET `$passwordCol` = :password WHERE id = :id");
        $st->execute([':password' => $hash, ':id' => $id]);

        $this->flash('success', 'Password reset successfully.');
        $this->redirect('/easychair/admin/users?' . http_build_query([
            'conference_id' => $_POST['conference_id'] ?? '',
            'q' => $_POST['q'] ?? '',
            'role' => $_POST['role'] ?? '',
            'page' => $_POST['page'] ?? 1,
        ]));
    }

    public function delete(): void
    {
        $this->requireSuperAdmin();
        $this->checkCsrf();

        $id = (int)($_POST['id'] ?? 0);
        $current = (int)($_SESSION['user_id'] ?? $_SESSION['id'] ?? 0);

        if ($id <= 0 || $id === $current) {
            $this->flash('danger', 'You cannot delete this user.');
            $this->redirect('/easychair/admin/users');
        }

        $this->db->beginTransaction();

        try {
            foreach ([
                'conference_user_roles',
                'user_conferences',
                'conference_reviewers',
                'track_chair_assignments',
                'review_assignments',
                'business_role_permissions',
            ] as $tbl) {
                if ($this->tableExists($tbl) && $this->hasCol($tbl, 'user_id')) {
                    $st = $this->db->prepare("DELETE FROM `$tbl` WHERE user_id = ?");
                    $st->execute([$id]);
                }
            }

            if ($this->tableExists('review_assignments') && $this->hasCol('review_assignments', 'reviewer_id')) {
                $st = $this->db->prepare("DELETE FROM review_assignments WHERE reviewer_id = ?");
                $st->execute([$id]);
            }

            $st = $this->db->prepare("DELETE FROM users WHERE id = ?");
            $st->execute([$id]);

            $this->db->commit();
            $this->flash('success', 'User deleted successfully.');
        } catch (Throwable $e) {
            $this->db->rollBack();
            $this->flash('danger', 'Delete failed: ' . $e->getMessage());
        }

        $this->redirect('/easychair/admin/users?' . http_build_query([
            'conference_id' => $_POST['conference_id'] ?? '',
            'q' => $_POST['q'] ?? '',
            'role' => $_POST['role'] ?? '',
            'page' => $_POST['page'] ?? 1,
        ]));
    }
}
