<?php

namespace App\Controllers;

use App\Core\Auth;
use App\Core\AuditLog;
use App\Core\Permission;
use App\Core\Router;
use App\Models\UserManager;
use App\Models\Lookup;

class AdminController
{
    public function users(): void
    {
        $admin = Permission::requireSuperAdmin();
        $search = trim($_GET['q'] ?? '');
        $users  = UserManager::all($search);
        $departments = Lookup::departments();
        $projectsByDept = Lookup::projectsByDepartment();
        $roles = Lookup::roles();
        $availableManagers = Lookup::availableManagers();
        $allManagersForDisplay = Lookup::allManagersForDisplay();
        $availableEmployees = Lookup::availableEmployees();
        $reportsToCandidates = Lookup::reportsToCandidates();

        $db = \App\Core\Database::connection();
        $stats = [
            'total_users'    => (int)$db->query("SELECT (SELECT COUNT(*) FROM superadmins) + (SELECT COUNT(*) FROM managers WHERE username IS NOT NULL) + (SELECT COUNT(*) FROM employees WHERE username IS NOT NULL) AS c")->fetch()['c'],
            'active_users'   => (int)$db->query("SELECT (SELECT COUNT(*) FROM superadmins) + (SELECT COUNT(*) FROM managers WHERE username IS NOT NULL AND is_active=1) + (SELECT COUNT(*) FROM employees WHERE username IS NOT NULL AND is_active=1) AS c")->fetch()['c'],
            'departments'    => (int)$db->query("SELECT COUNT(*) c FROM departments WHERE is_active=1")->fetch()['c'],
            'total_projects' => (int)$db->query("SELECT COUNT(*) c FROM projects")->fetch()['c'],
        ];

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

        require __DIR__ . '/../Views/admin/users.php';
    }

    public function userCreate(): void
    {
        Permission::requireSuperAdmin();

        $type = $_POST['user_type'] ?? 'employee';
        $existingId = (int)($_POST['existing_id'] ?? 0);
        $newPersonName = trim($_POST['new_person_name'] ?? '');
        $username = trim($_POST['username'] ?? '');
        $email = trim($_POST['email'] ?? '');
        $password = $_POST['password'] ?? '';
        $roleId = $_POST['role_id'] ?? null;
        $deptIds = $_POST['department_ids'] ?? [];
        $projIds = $_POST['project_ids'] ?? [];
        $reportsTo = $_POST['reports_to'] ?? '';

        // New: if the Super Admin typed a name instead of picking from the
        // imported list, create that record first, then proceed exactly as
        // if they had picked an existing person — grantAccess() below is
        // untouched either way.
        if ($existingId <= 0 && $newPersonName !== '') {
            try {
                $existingId = UserManager::createNewPerson($type, $newPersonName);
            } catch (\Throwable $e) {
                $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Could not add new person: ' . $e->getMessage()];
                Router::redirect('/admin/users');
            }
        }

        if ($existingId <= 0) {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Please select a person to grant access to, or enter a name to add someone new.'];
            Router::redirect('/admin/users');
        }

        try {
            $creds = UserManager::grantAccess($type, $existingId, [
                'username' => $username, 'email' => $email,
                'password' => $password, 'role_id' => $roleId,
                'department_ids' => $deptIds, 'project_ids' => $projIds,
            ]);

            if ($reportsTo !== '') {
                [$rtType, $rtId] = array_pad(explode(':', $reportsTo, 2), 2, null);
                if (in_array($rtType, ['manager', 'superadmin'], true) && ctype_digit((string)$rtId)) {
                    UserManager::setReportsTo($type, $existingId, $rtType, (int)$rtId);
                }
            }

            $actor = Auth::currentUser();
            AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'user', (string)$existingId, 'create', null, ['username' => $creds['username'], 'type' => $type]);

            $_SESSION['flash'] = [
                'type' => 'success',
                'msg'  => "Login access granted. Username: \"{$creds['username']}\" · Temporary Password: \"{$creds['password']}\" — copy this now, it won't be shown again. They'll be required to set a new password on first login.",
            ];
        } catch (\Throwable $e) {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Could not grant access: ' . $e->getMessage()];
        }

        Router::redirect('/admin/users');
    }

    public function userToggle(): void
    {
        Permission::requireSuperAdmin();
        $type = $_POST['user_type'] ?? '';
        $id   = (int)($_POST['id'] ?? 0);
        $active = ($_POST['active'] ?? '0') === '1';

        UserManager::toggleActive($type, $id, $active);

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'user', (string)$id, $active ? 'enable' : 'disable');

        $_SESSION['flash'] = ['type' => 'success', 'msg' => 'User status updated.'];
        Router::redirect('/admin/users');
    }

    public function userUpdateAccess(): void
    {
        Permission::requireSuperAdmin();

        $type = $_POST['user_type'] ?? '';
        $id   = (int)($_POST['id'] ?? 0);
        $roleId  = $_POST['role_id'] ?? null;
        $deptIds = $_POST['department_ids'] ?? [];
        $projIds = $_POST['project_ids'] ?? [];
        $reportsTo = $_POST['reports_to'] ?? ''; // format: "manager:5" or "superadmin:1" or ''

        if ($roleId) {
            UserManager::setRole($type, $id, (int)$roleId);
        }
        UserManager::setDepartments($type, $id, $deptIds);
        UserManager::setProjects($type, $id, $projIds);

        if ($reportsTo === '') {
            UserManager::setReportsTo($type, $id, null, null);
        } else {
            [$rtType, $rtId] = array_pad(explode(':', $reportsTo, 2), 2, null);
            if (!in_array($rtType, ['manager', 'superadmin'], true) || !ctype_digit((string)$rtId)) {
                $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Invalid Reports To selection. Other access changes were saved.'];
                Router::redirect('/admin/users');
            }
            if ((int)$rtId === $id && $rtType === $type) {
                $_SESSION['flash'] = ['type' => 'error', 'msg' => 'A user cannot report to themselves. Other access changes were saved, but Reports To was not.'];
                Router::redirect('/admin/users');
            }
            UserManager::setReportsTo($type, $id, $rtType, (int)$rtId);
        }

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'user', (string)$id, 'permission_change', null, [
            'role_id' => $roleId, 'department_ids' => $deptIds, 'project_ids' => $projIds, 'reports_to' => $reportsTo,
        ]);

        $_SESSION['flash'] = ['type' => 'success', 'msg' => 'Access updated successfully.'];
        Router::redirect('/admin/users');
    }

    /**
     * Backfill login credentials for every existing manager (and any employees who
     * already have a role/department assigned) who don't have a username set yet.
     * Does NOT touch role/department/project assignments already on file - only
     * fills in username + temporary password for people who have none.
     */
    public function bulkGenerateCredentials(): void
    {
        Permission::requireSuperAdmin();
        $actor = Auth::currentUser();

        $targets = array_merge(
            array_map(fn($m) => ['type' => 'manager', 'id' => (int)$m['id']], Lookup::availableManagers()),
            array_map(fn($e) => ['type' => 'employee', 'id' => (int)$e['id']], Lookup::availableEmployees())
        );

        $generated = [];
        foreach ($targets as $t) {
            try {
                $creds = UserManager::grantAccess($t['type'], $t['id'], []); // empty data = auto-generate only, don't touch role/dept/project
                $generated[] = [
                    'name'     => UserManager::nameFor($t['type'], $t['id']),
                    'type'     => $t['type'],
                    'username' => $creds['username'],
                    'password' => $creds['password'],
                ];
                AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'user', (string)$t['id'], 'create', null, ['username' => $creds['username'], 'bulk' => true]);
            } catch (\Throwable $e) {
                // skip anyone that fails, keep going for the rest
            }
        }

        $_SESSION['bulk_credentials'] = $generated;
        Router::redirect('/admin/users/bulk-credentials-result');
    }

    public function bulkCredentialsResult(): void
    {
        $admin = Permission::requireSuperAdmin();
        $generated = $_SESSION['bulk_credentials'] ?? [];
        unset($_SESSION['bulk_credentials']);
        require __DIR__ . '/../Views/admin/bulk_credentials_result.php';
    }

    public function userResetPassword(): void
    {
        Permission::requireSuperAdmin();

        $type = $_POST['user_type'] ?? '';
        $id   = (int)($_POST['id'] ?? 0);
        $newPassword = $_POST['new_password'] ?? '';

        if (strlen($newPassword) < 8) {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'New password must be at least 8 characters.'];
            Router::redirect('/admin/users');
        }

        try {
            UserManager::adminResetPassword($type, $id, $newPassword);

            $actor = Auth::currentUser();
            AuditLog::record(
                $actor['user_type'], $actor['user_id'], $actor['name'],
                'user', (string)$id, 'password_reset',
                null, ['reset_by' => $actor['name'], 'reset_by_type' => $actor['user_type']]
            );

            $_SESSION['flash'] = [
                'type' => 'success',
                'msg'  => "Password reset. New Temporary Password: \"{$newPassword}\" — copy this now, it won't be shown again. They'll be required to set a new password on next login.",
            ];
        } catch (\Throwable $e) {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Could not reset password: ' . $e->getMessage()];
        }

        Router::redirect('/admin/users');
    }

    public function auditLogs(): void
    {
        Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();
        $logs = $db->query("SELECT * FROM audit_log ORDER BY created_at DESC LIMIT 200")->fetchAll();
        require __DIR__ . '/../Views/admin/audit_logs.php';
    }

    public function departments(): void
    {
        $admin = Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();
        $departments = $db->query(
            "SELECT d.*, (SELECT COUNT(*) FROM projects p WHERE p.department_id = d.id) AS project_count
             FROM departments d ORDER BY d.name"
        )->fetchAll();

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

        require __DIR__ . '/../Views/admin/departments.php';
    }

    public function departmentCreate(): void
    {
        Permission::requireSuperAdmin();
        $name = trim($_POST['name'] ?? '');
        $code = trim($_POST['code'] ?? '');

        if ($name === '' || $code === '') {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Department name and code are required.'];
            Router::redirect('/admin/departments');
        }

        $db = \App\Core\Database::connection();
        $stmt = $db->prepare("INSERT INTO departments (name, code, is_active) VALUES (:n, :c, 1)");
        $stmt->execute(['n' => $name, 'c' => $code]);

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'department', (string)$db->lastInsertId(), 'create', null, ['name' => $name, 'code' => $code]);

        $_SESSION['flash'] = ['type' => 'success', 'msg' => "Department \"{$name}\" created."];
        Router::redirect('/admin/departments');
    }

    public function departmentToggle(): void
    {
        Permission::requireSuperAdmin();
        $id = (int)($_POST['id'] ?? 0);
        $active = ($_POST['active'] ?? '0') === '1';

        $db = \App\Core\Database::connection();
        $db->prepare("UPDATE departments SET is_active = :a WHERE id = :id")->execute(['a' => $active ? 1 : 0, 'id' => $id]);

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'department', (string)$id, $active ? 'enable' : 'disable');

        $_SESSION['flash'] = ['type' => 'success', 'msg' => 'Department status updated.'];
        Router::redirect('/admin/departments');
    }

    public function settings(): void
    {
        $admin = Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();
        $rows = $db->query("SELECT setting_key, setting_value FROM system_settings")->fetchAll();
        $settings = [];
        foreach ($rows as $r) { $settings[$r['setting_key']] = $r['setting_value']; }

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

        require __DIR__ . '/../Views/admin/settings.php';
    }

    public function settingsSave(): void
    {
        Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();

        $fields = ['app_name', 'session_timeout_minutes', 'max_login_attempts', 'require_2fa_for_admins'];
        $stmt = $db->prepare("INSERT INTO system_settings (setting_key, setting_value) VALUES (:k, :v) ON DUPLICATE KEY UPDATE setting_value = :v2");

        foreach ($fields as $f) {
            $value = $_POST[$f] ?? '';
            if ($f === 'require_2fa_for_admins') { $value = isset($_POST[$f]) ? '1' : '0'; }
            $stmt->execute(['k' => $f, 'v' => $value, 'v2' => $value]);
        }

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'settings', '', 'update');

        $_SESSION['flash'] = ['type' => 'success', 'msg' => 'Settings saved.'];
        Router::redirect('/admin/settings');
    }

    public function projects(): void
    {
        $admin = Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();
        $projects = $db->query(
            "SELECT p.*, d.name AS department_name FROM projects p JOIN departments d ON d.id = p.department_id ORDER BY d.name, p.name"
        )->fetchAll();
        $departments = Lookup::departments();

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

        require __DIR__ . '/../Views/admin/projects.php';
    }

    public function projectSave(): void
    {
        Permission::requireSuperAdmin();
        $db = \App\Core\Database::connection();

        $id = (int)($_POST['id'] ?? 0);
        $name = trim($_POST['name'] ?? '');
        $code = trim($_POST['code'] ?? '');
        $deptId = (int)($_POST['department_id'] ?? 0);
        $status = $_POST['status'] ?? 'active';
        $kpiFormType = $_POST['kpi_form_type'] ?? 'none';
        if (!in_array($kpiFormType, ['none','scheduling','ops_manager','accounts'], true)) {
            $kpiFormType = 'none';
        }

        if ($name === '' || $code === '' || $deptId <= 0) {
            $_SESSION['flash'] = ['type' => 'error', 'msg' => 'Project name, code, and department are required.'];
            Router::redirect('/admin/projects');
        }

        $actor = Auth::currentUser();

        if ($id > 0) {
            $db->prepare("UPDATE projects SET name=:n, code=:c, department_id=:d, status=:s, kpi_form_type=:kft WHERE id=:id")
               ->execute(['n' => $name, 'c' => $code, 'd' => $deptId, 's' => $status, 'kft' => $kpiFormType, 'id' => $id]);
            AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'project', (string)$id, 'update', null, ['name' => $name]);
            $_SESSION['flash'] = ['type' => 'success', 'msg' => "Project \"{$name}\" updated."];
        } else {
            $db->prepare("INSERT INTO projects (name, code, department_id, status, kpi_form_type) VALUES (:n, :c, :d, :s, :kft)")
               ->execute(['n' => $name, 'c' => $code, 'd' => $deptId, 's' => $status, 'kft' => $kpiFormType]);
            $newId = (int)$db->lastInsertId();
            AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'project', (string)$newId, 'create', null, ['name' => $name]);
            $_SESSION['flash'] = ['type' => 'success', 'msg' => "Project \"{$name}\" created."];
        }

        Router::redirect('/admin/projects');
    }

    public function projectArchive(): void
    {
        Permission::requireSuperAdmin();
        $id = (int)($_POST['id'] ?? 0);
        $status = $_POST['status'] ?? 'archived';

        $db = \App\Core\Database::connection();
        $db->prepare("UPDATE projects SET status=:s WHERE id=:id")->execute(['s' => $status, 'id' => $id]);

        $actor = Auth::currentUser();
        AuditLog::record($actor['user_type'], $actor['user_id'], $actor['name'], 'project', (string)$id, 'update', null, ['status' => $status]);

        $_SESSION['flash'] = ['type' => 'success', 'msg' => 'Project status updated.'];
        Router::redirect('/admin/projects');
    }

    public function resetTestData(): void
    {
        // View handles its own Permission::requireSuperAdmin() check
        require __DIR__ . '/../Views/admin/reset_test_data.php';
    }
}
