<?php
declare(strict_types=1);

namespace App\Support;

final class Auth
{
    private const WEB_AUTH_KEY = 'erp_web_authenticated';
    private const WEB_LOGIN_KEY = 'erp_web_login';
    private const WEB_PROVIDER_KEY = 'erp_web_provider';
    private const WEB_NAME_KEY = 'erp_web_name';
    private const WEB_FINGERPRINT_KEY = 'erp_web_auth_fingerprint';
    private const WEB_ACTIVITY_KEY = 'erp_web_last_activity';
    private const WEB_INTENDED_URL_KEY = 'erp_web_intended_url';
    private const GOOGLE_STATE_KEY = 'erp_google_oauth_state';
    private const GOOGLE_STATE_TIME_KEY = 'erp_google_oauth_state_time';

    public static function requireApiToken(): void
    {
        $config = require __DIR__ . '/../config.php';
        $expected = (string)($config['api_token'] ?? '');

        if ($expected === '') {
            return;
        }

        $provided = $_SERVER['HTTP_X_API_TOKEN'] ?? ($_GET['token'] ?? '');
        if (!hash_equals($expected, (string)$provided)) {
            Response::error('Unauthorized', 401);
            exit;
        }
    }

    public static function requireWebLogin(): void
    {
        if (self::isWebAuthenticated()) {
            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
            header('Pragma: no-cache');
            return;
        }

        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET') {
            $requestUri = (string)($_SERVER['REQUEST_URI'] ?? '');
            if ($requestUri !== '' && str_starts_with($requestUri, '/') && !str_starts_with($requestUri, '//')) {
                $_SESSION[self::WEB_INTENDED_URL_KEY] = $requestUri;
            }
        }
        header('Location: login.php');
        exit;
    }

    public static function isWebAuthConfigured(): bool
    {
        $config = self::webAuthConfig();
        return $config['login'] !== ''
            && preg_match('/^[a-f0-9]{64}$/', $config['password_sha256']) === 1;
    }

    public static function isWebAuthenticated(): bool
    {
        self::startWebSession();
        if (empty($_SESSION[self::WEB_AUTH_KEY])) {
            return false;
        }
        $_SESSION[self::WEB_ACTIVITY_KEY] = time();
        return true;
    }

    public static function attemptWebLogin(string $login, string $password): bool
    {
        self::startWebSession();

        $dbUser = self::databaseWebUser(trim($login));
        if ($dbUser !== null && hash_equals(strtolower((string)$dbUser['password_sha256']), hash('sha256', $password))) {
            self::applyDatabaseWebSession($dbUser);
            return true;
        }

        if (!self::isWebAuthConfigured()) {
            return false;
        }

        $config = self::webAuthConfig();
        $loginMatches = hash_equals($config['login'], trim($login));
        $passwordMatches = hash_equals($config['password_sha256'], hash('sha256', $password));
        if (!$loginMatches || !$passwordMatches) {
            usleep(300000);
            return false;
        }

        session_regenerate_id(true);
        $_SESSION[self::WEB_AUTH_KEY] = true;
        $_SESSION[self::WEB_LOGIN_KEY] = $config['login'];
        $_SESSION[self::WEB_PROVIDER_KEY] = 'local';
        $_SESSION[self::WEB_NAME_KEY] = self::localDisplayName($config['login']);
        $_SESSION[self::WEB_FINGERPRINT_KEY] = self::localFingerprint($config);
        $_SESSION['erp_user_id'] = 1;
        $_SESSION['erp_user_role'] = 'admin';
        $_SESSION['erp_menu_permissions'] = json_encode(array_keys(self::defaultMenuPermissions()), JSON_UNESCAPED_UNICODE);
        $_SESSION['erp_mail_login'] = $config['login'] . '@lawyerstarerp.com';
        $_SESSION[self::WEB_ACTIVITY_KEY] = time();
        $_SESSION['erp_user_id'] = 1;
        $_SESSION['erp_user_role'] = 'admin';
        $_SESSION['erp_menu_permissions'] = json_encode(array_keys(self::defaultMenuPermissions()), JSON_UNESCAPED_UNICODE);
        $_SESSION['erp_mail_login'] = $config['login'] . '@lawyerstarerp.com';
        return true;
    }

    public static function isGoogleWebAuthConfigured(): bool
    {
        $config = self::googleOAuthConfig();
        $hasAllowList = $config['allowed_emails'] !== '' || $config['allowed_domain'] !== '';
        return $config['client_id'] !== ''
            && $config['client_secret'] !== ''
            && filter_var($config['redirect_uri'], FILTER_VALIDATE_URL) !== false
            && $hasAllowList;
    }

    public static function googleOAuthConfig(): array
    {
        $config = require __DIR__ . '/../config.php';
        $googleAuth = (array)($config['google_auth'] ?? []);
        return [
            'client_id' => trim((string)($googleAuth['client_id'] ?? '')),
            'client_secret' => trim((string)($googleAuth['client_secret'] ?? '')),
            'redirect_uri' => trim((string)($googleAuth['redirect_uri'] ?? '')),
            'allowed_emails' => strtolower(trim((string)($googleAuth['allowed_emails'] ?? ''))),
            'allowed_domain' => strtolower(ltrim(trim((string)($googleAuth['allowed_domain'] ?? '')), '@')),
        ];
    }

    public static function createGoogleOAuthState(): string
    {
        self::startWebSession();
        $state = bin2hex(random_bytes(32));
        $_SESSION[self::GOOGLE_STATE_KEY] = hash('sha256', $state);
        $_SESSION[self::GOOGLE_STATE_TIME_KEY] = time();
        return $state;
    }

    public static function consumeGoogleOAuthState(string $state): bool
    {
        self::startWebSession();
        $expected = (string)($_SESSION[self::GOOGLE_STATE_KEY] ?? '');
        $createdAt = (int)($_SESSION[self::GOOGLE_STATE_TIME_KEY] ?? 0);
        unset($_SESSION[self::GOOGLE_STATE_KEY], $_SESSION[self::GOOGLE_STATE_TIME_KEY]);

        return $state !== ''
            && $expected !== ''
            && $createdAt > 0
            && time() - $createdAt <= 600
            && hash_equals($expected, hash('sha256', $state));
    }

    public static function completeGoogleWebLogin(array $profile): bool
    {
        self::startWebSession();
        if (!self::isGoogleWebAuthConfigured()) {
            return false;
        }

        $email = strtolower(trim((string)($profile['email'] ?? '')));
        $emailVerified = $profile['email_verified'] ?? false;
        $isVerified = $emailVerified === true || $emailVerified === 1 || $emailVerified === 'true';
        $subject = trim((string)($profile['sub'] ?? ''));
        if (
            !$isVerified
            || $subject === ''
            || filter_var($email, FILTER_VALIDATE_EMAIL) === false
            || !self::isGoogleEmailAllowed($email)
        ) {
            return false;
        }

        $name = trim((string)($profile['name'] ?? ''));
        // session_regenerate_id(true);
        $_SESSION[self::WEB_AUTH_KEY] = true;
        $_SESSION[self::WEB_LOGIN_KEY] = $email;
        $_SESSION[self::WEB_PROVIDER_KEY] = 'google';
        $_SESSION[self::WEB_NAME_KEY] = $name !== '' ? $name : $email;
        $_SESSION[self::WEB_FINGERPRINT_KEY] = self::googleFingerprint($email);
        $_SESSION[self::WEB_ACTIVITY_KEY] = time();
        return true;
    }

    public static function logoutWeb(): void
    {
        self::startWebSession();
        self::clearWebSessionData();
        $_SESSION = [];
        if (ini_get('session.use_cookies')) {
            $params = session_get_cookie_params();
            setcookie(session_name(), '', [
                'expires' => time() - 42000,
                'path' => $params['path'],
                'domain' => $params['domain'],
                'secure' => (bool)$params['secure'],
                'httponly' => (bool)$params['httponly'],
                'samesite' => 'Lax',
            ]);
        }
        session_destroy();
    }

    public static function consumeIntendedWebUrl(): string
    {
        self::startWebSession();
        $url = (string)($_SESSION[self::WEB_INTENDED_URL_KEY] ?? '');
        unset($_SESSION[self::WEB_INTENDED_URL_KEY]);
        return $url !== '' && str_starts_with($url, '/') && !str_starts_with($url, '//')
            ? $url
            : 'index.php';
    }

    public static function currentWebLogin(): string
    {
        self::startWebSession();
        return (string)($_SESSION[self::WEB_NAME_KEY] ?? $_SESSION[self::WEB_LOGIN_KEY] ?? '');
    }

    public static function configuredWebLogin(): string
    {
        return self::webAuthConfig()['login'];
    }

    public static function verifyLocalPassword(string $password): bool
    {
        $config = self::webAuthConfig();
        return self::isWebAuthConfigured()
            && hash_equals($config['password_sha256'], hash('sha256', $password));
    }

    public static function refreshLocalWebSession(): void
    {
        self::startWebSession();
        if ((string)($_SESSION[self::WEB_PROVIDER_KEY] ?? '') !== 'local') {
            return;
        }
        $config = self::webAuthConfig();
        if ($config['login'] === '' || preg_match('/^[a-f0-9]{64}$/', $config['password_sha256']) !== 1) {
            self::clearWebSessionData();
            return;
        }
        $_SESSION[self::WEB_LOGIN_KEY] = $config['login'];
        $_SESSION[self::WEB_NAME_KEY] = self::localDisplayName($config['login']);
        $_SESSION[self::WEB_FINGERPRINT_KEY] = self::localFingerprint($config);
        $_SESSION['erp_user_id'] = 1;
        $_SESSION['erp_user_role'] = 'admin';
        $_SESSION['erp_menu_permissions'] = json_encode(array_keys(self::defaultMenuPermissions()), JSON_UNESCAPED_UNICODE);
        $_SESSION['erp_mail_login'] = $config['login'] . '@lawyerstarerp.com';
        $_SESSION[self::WEB_ACTIVITY_KEY] = time();
    }

    private static function databaseWebUser(string $login): ?array
    {
        if ($login === '' || !class_exists(Database::class)) {
            return null;
        }
        try {
            $pdo = Database::connection();
            $stmt = $pdo->prepare(
                "SELECT id, login, password_sha256, ad_soyad, rol, aktiv, menu_icazeleri, mail_login
                 FROM erp_istifadeci_profili
                 WHERE aktiv=1 AND login=?
                 LIMIT 1"
            );
            $stmt->execute([$login]);
            $user = $stmt->fetch();
            return is_array($user) ? $user : null;
        } catch (\Throwable) {
            return null;
        }
    }

    private static function applyDatabaseWebSession(array $user): void
    {
        session_regenerate_id(true);
        $login = (string)($user['login'] ?? '');
        $role = (string)($user['rol'] ?? 'user');
        $permissions = (string)($user['menu_icazeleri'] ?? '');
        if ($role === 'admin' || $permissions === '') {
            $permissions = json_encode(array_keys(self::defaultMenuPermissions()), JSON_UNESCAPED_UNICODE);
        }
        $_SESSION[self::WEB_AUTH_KEY] = true;
        $_SESSION[self::WEB_LOGIN_KEY] = $login;
        $_SESSION[self::WEB_PROVIDER_KEY] = 'local';
        $_SESSION[self::WEB_NAME_KEY] = (string)($user['ad_soyad'] ?: self::localDisplayName($login));
        $_SESSION[self::WEB_FINGERPRINT_KEY] = self::databaseFingerprint($user);
        $_SESSION[self::WEB_ACTIVITY_KEY] = time();
        $_SESSION['erp_user_id'] = (int)($user['id'] ?? 0);
        $_SESSION['erp_user_role'] = $role;
        $_SESSION['erp_menu_permissions'] = $permissions;
        $_SESSION['erp_mail_login'] = (string)($user['mail_login'] ?: ($login . '@lawyerstarerp.com'));
    }

    private static function databaseFingerprint(array $user): string
    {
        return hash('sha256', 'db|' . (int)($user['id'] ?? 0) . '|' . (string)($user['login'] ?? '') . '|' . (string)($user['password_sha256'] ?? '') . '|' . (string)($user['rol'] ?? 'user') . '|' . (string)($user['menu_icazeleri'] ?? ''));
    }

    private static function databaseSessionValid(): bool
    {
        $userId = (int)($_SESSION['erp_user_id'] ?? 0);
        if ($userId < 1 || !class_exists(Database::class)) {
            return false;
        }
        try {
            $pdo = Database::connection();
            $stmt = $pdo->prepare(
                "SELECT id, login, password_sha256, ad_soyad, rol, aktiv, menu_icazeleri, mail_login
                 FROM erp_istifadeci_profili
                 WHERE id=? AND aktiv=1
                 LIMIT 1"
            );
            $stmt->execute([$userId]);
            $user = $stmt->fetch();
            if (!is_array($user)) {
                return false;
            }
            $fingerprint = (string)($_SESSION[self::WEB_FINGERPRINT_KEY] ?? '');
            if (!hash_equals(self::databaseFingerprint($user), $fingerprint)) {
                return false;
            }
            $_SESSION['erp_user_role'] = (string)($user['rol'] ?? 'user');
            $_SESSION['erp_menu_permissions'] = (string)($user['menu_icazeleri'] ?? '');
            $_SESSION['erp_mail_login'] = (string)($user['mail_login'] ?: ((string)$user['login'] . '@lawyerstarerp.com'));
            return true;
        } catch (\Throwable) {
            return false;
        }
    }

    private static function defaultMenuPermissions(): array
    {
        return [
            'home' => 'Ana səhifə',
            'isler' => 'Məhkəmə işləri',
            'iclaslar' => 'İclaslar',
            'tasks' => 'Tapşırıqlar',
            'icra' => 'İcra işləri',
            'cinayet' => 'Cinayət işləri',
            'telimler' => 'Təlimlər',
            'crm' => 'CRM',
            'huquqi_baza' => 'Hüquqi baza',
            'mehkemeler' => 'Məhkəmələr',
            'hakimler' => 'Hakimlər',
            'icra_shobeler' => 'İcra şöbələri',
            'icra_memurlari' => 'İcra məmurları',
            'abuneciler' => 'Abunəçilər',
            'profil' => 'Ayarlar',
            'sifre_deyis' => 'Şifrəni dəyişmək',
            'istifadeciler' => 'İstifadəçilər',
        ];
    }
    private static function startWebSession(): void
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            return;
        }

        $forwardedProto = strtolower(trim(explode(',', (string)($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? ''))[0] ?? ''));
        $isSecure = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off')
            || $forwardedProto === 'https';
        ini_set('session.use_strict_mode', '1');
        session_name('lawyerstar_erp');
        session_set_cookie_params([
            'lifetime' => 0,
            'path' => '/',
            'domain' => '',
            'secure' => $isSecure,
            'httponly' => true,
            'samesite' => 'Lax',
        ]);
        session_start();
    }

    private static function clearWebSessionData(): void
    {
        unset(
            $_SESSION['erp_user_id'],
            $_SESSION['erp_user_role'],
            $_SESSION['erp_menu_permissions'],
            $_SESSION['erp_mail_login'],
            $_SESSION[self::WEB_AUTH_KEY],
            $_SESSION[self::WEB_LOGIN_KEY],
            $_SESSION[self::WEB_PROVIDER_KEY],
            $_SESSION[self::WEB_NAME_KEY],
            $_SESSION[self::WEB_FINGERPRINT_KEY],
            $_SESSION[self::WEB_ACTIVITY_KEY]
        );
    }

    private static function isGoogleEmailAllowed(string $email): bool
    {
        $email = strtolower(trim($email));
        if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
            return false;
        }

        $config = self::googleOAuthConfig();
        $allowedEmails = array_values(array_filter(array_map(
            static fn(string $value): string => strtolower(trim($value)),
            explode(',', $config['allowed_emails'])
        )));
        if (in_array($email, $allowedEmails, true)) {
            return true;
        }

        $domain = $config['allowed_domain'];
        $emailDomain = strtolower((string)substr(strrchr($email, '@') ?: '', 1));
        return $domain !== '' && hash_equals($domain, $emailDomain);
    }

    private static function localFingerprint(array $config): string
    {
        return hash('sha256', 'local|' . $config['login'] . '|' . $config['password_sha256']);
    }

    private static function googleFingerprint(string $email): string
    {
        $config = self::googleOAuthConfig();
        return hash('sha256', 'google|' . $config['client_id'] . '|' . strtolower(trim($email)));
    }

    private static function webAuthConfig(): array
    {
        $config = require __DIR__ . '/../config.php';
        $webAuth = (array)($config['web_auth'] ?? []);
        $resolved = [
            'login' => trim((string)($webAuth['login'] ?? '')),
            'password_sha256' => strtolower(trim((string)($webAuth['password_sha256'] ?? ''))),
            'session_ttl' => (int)($webAuth['session_ttl'] ?? 28800),
        ];
        try {
            $profile = Database::connection()->query(
                'SELECT login, password_sha256 FROM erp_istifadeci_profili WHERE id=1 LIMIT 1'
            )->fetch();
            if (is_array($profile)) {
                $storedLogin = trim((string)($profile['login'] ?? ''));
                $storedHash = strtolower(trim((string)($profile['password_sha256'] ?? '')));
                if ($storedLogin !== '') {
                    $resolved['login'] = $storedLogin;
                }
                if (preg_match('/^[a-f0-9]{64}$/', $storedHash) === 1) {
                    $resolved['password_sha256'] = $storedHash;
                }
            }
        } catch (\Throwable) {
            // Migration tətbiq olunana qədər mövcud .env giriş məlumatlarından istifadə olunur.
        }
        return $resolved;
    }

    private static function localDisplayName(string $fallback): string
    {
        try {
            $profile = Database::connection()->query(
                'SELECT ad, soyad FROM erp_istifadeci_profili WHERE id=1 LIMIT 1'
            )->fetch();
            if (is_array($profile)) {
                $name = trim(trim((string)($profile['ad'] ?? '')) . ' ' . trim((string)($profile['soyad'] ?? '')));
                if ($name !== '') {
                    return $name;
                }
            }
        } catch (\Throwable) {
            // Profil cədvəli yoxdursa login adı göstərilir.
        }
        return $fallback;
    }
}
