<?php

declare(strict_types=1);

namespace Flowaxy\Domain\User\Services;

use Flowaxy\Contracts\Domain\User\AdminUserRepositoryInterface;
use Flowaxy\Contracts\Domain\User\AdminRoleRepositoryInterface;
use Flowaxy\Domain\User\Services\RootUserConfig;
use Flowaxy\Support\Facades\Hash;
use Flowaxy\Support\Facades\Log;
use Throwable;

use function bin2hex;
use function class_exists;
use function date;
use function file_exists;
use function is_readable;
use const DIRECTORY_SEPARATOR;
use const DS;

// Сервіс аутентифікації адміністратора
final class AuthenticateAdminUserService
{
    public function __construct(
        private readonly AdminUserRepositoryInterface $users,
        private readonly ?AdminRoleRepositoryInterface $roles = null
    ) {
    }

    public function execute(string $username, string $password): AuthenticationResult
    {
        // Диагностика: логируем начало авторизации
        error_log("AuthenticateAdminUserService::execute: Starting authentication. Username: '{$username}', Password length: " . strlen($password));

        if ($username === '' || $password === '') {
            error_log("AuthenticateAdminUserService::execute: Empty username or password");
            try {
                Log::Warning('AuthenticateAdminUserService: Empty username or password');
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Заповніть всі поля');
        }

        // Проверка root пользователя (не хранится в БД)
        try {
            error_log("AuthenticateAdminUserService::execute: Checking if RootUserConfig class exists: " . (class_exists(RootUserConfig::class) ? 'yes' : 'no'));

            if (!class_exists(RootUserConfig::class)) {
                error_log("AuthenticateAdminUserService::execute: RootUserConfig class not found, trying to load...");

                // Пробуем загрузить класс через autoloader
                if (function_exists('spl_autoload_call')) {
                    \spl_autoload_call(RootUserConfig::class);
                }

                // Если autoloader не помог, пробуем загрузить напрямую
                if (!class_exists(RootUserConfig::class)) {
                    $rootUserConfigFile = \Flowaxy\Core\System\PathResolver::flowaxy() .
                        (defined('DS') ? DS : DIRECTORY_SEPARATOR) .
                        'Domain' .
                        (defined('DS') ? DS : DIRECTORY_SEPARATOR) .
                        'User' .
                        (defined('DS') ? DS : DIRECTORY_SEPARATOR) .
                        'Services' .
                        (defined('DS') ? DS : DIRECTORY_SEPARATOR) .
                        'RootUserConfig.php';

                    error_log("AuthenticateAdminUserService::execute: Trying to load RootUserConfig from: {$rootUserConfigFile}, Exists: " . (file_exists($rootUserConfigFile) ? 'yes' : 'no'));

                    if (file_exists($rootUserConfigFile) && is_readable($rootUserConfigFile)) {
                        require_once $rootUserConfigFile;
                        error_log("AuthenticateAdminUserService::execute: RootUserConfig file loaded, class exists: " . (class_exists(RootUserConfig::class) ? 'yes' : 'no'));
                    } else {
                        error_log("AuthenticateAdminUserService::execute: RootUserConfig file not found or not readable: {$rootUserConfigFile}");
                    }
                }
            }

            if (!class_exists(RootUserConfig::class)) {
                error_log("AuthenticateAdminUserService::execute: RootUserConfig class still not found after loading attempts, continuing with DB authentication");
                // Продолжаем с обычной авторизацией через БД
            } else {
                $isRoot = RootUserConfig::isRootUsername($username);
                error_log("AuthenticateAdminUserService::execute: Is root username: " . ($isRoot ? 'yes' : 'no'));

                if ($isRoot) {
                    error_log("AuthenticateAdminUserService::execute: Attempting root user authentication");
                    return $this->authenticateRootUser($password);
                }
            }
        } catch (Throwable $e) {
            error_log("AuthenticateAdminUserService::execute: Exception in isRootUsername check: " . $e->getMessage() . " | File: " . $e->getFile() . " | Line: " . $e->getLine() . " | Trace: " . $e->getTraceAsString());
            // Продолжаем с обычной авторизацией через БД
        }

        // Обычная аутентификация через БД
        $user = $this->users->findByUsername($username);
        if ($user === null) {
            try {
                Log::Warning('AuthenticateAdminUserService: User not found', ['username' => $username]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Невірний логін або пароль');
        }

        $passwordHash = $user->passwordHash ?? '';
        if (empty($passwordHash)) {
            try {
                Log::Error('AuthenticateAdminUserService: Password hash is empty', [
                    'user_id' => $user->id,
                    'username' => $username
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Невірний логін або пароль');
        }

        if (!($user->isActive ?? false)) {
            try {
                Log::Warning('AuthenticateAdminUserService: User is inactive', [
                    'user_id' => $user->id,
                    'username' => $username
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Невірний логін або пароль');
        }

        if (!Hash::check($password, $passwordHash)) {
            try {
                Log::Warning('AuthenticateAdminUserService: Password verification failed', [
                    'user_id' => $user->id,
                    'username' => $username,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Невірний логін або пароль');
        }

        // Проверяем права доступа к админ-панели
        error_log("AuthenticateAdminUserService::execute: Checking admin access for user_id: {$user->id}, roles repository available: " . ($this->roles !== null ? 'yes' : 'no'));
        $hasAdminAccess = $this->checkAdminAccess($user->id);
        error_log("AuthenticateAdminUserService::execute: Admin access check result: " . ($hasAdminAccess ? 'GRANTED' : 'DENIED'));

        if (!$hasAdminAccess) {
            error_log("AuthenticateAdminUserService::execute: User does not have admin access, returning error message");
            try {
                Log::Warning('AuthenticateAdminUserService: User does not have admin access', [
                    'user_id' => $user->id,
                    'username' => $username,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'У вас немає прав доступу');
        }

        $sessionToken = bin2hex(\random_bytes(32));
        $now = date('Y-m-d H:i:s');
        $this->users->updateSession($user->id, $sessionToken, $now);

        return new AuthenticationResult(true, userId: $user->id);
    }

    /**
     * Аутентификация root пользователя
     *
     * @param string $password
     * @return AuthenticationResult
     */
    private function authenticateRootUser(string $password): AuthenticationResult
    {
        error_log("AuthenticateAdminUserService::authenticateRootUser: Starting root authentication. Password length: " . strlen($password));

        try {
            $exists = RootUserConfig::exists();
            error_log("AuthenticateAdminUserService::authenticateRootUser: Root config exists: " . ($exists ? 'yes' : 'no'));

            if (!$exists) {
                error_log("AuthenticateAdminUserService::authenticateRootUser: Root user config does not exist");
                try {
                    Log::Warning('AuthenticateAdminUserService: Root user config does not exist');
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                return new AuthenticationResult(false, message: 'Невірний логін або пароль');
            }

            $passwordHash = RootUserConfig::getPasswordHash();
            error_log("AuthenticateAdminUserService::authenticateRootUser: Got password hash. Hash is null: " . ($passwordHash === null ? 'yes' : 'no') . ", Hash length: " . ($passwordHash !== null ? strlen($passwordHash) : '0'));

            $verified = RootUserConfig::verifyPassword($password);
            error_log("AuthenticateAdminUserService::authenticateRootUser: Password verification result: " . ($verified ? 'SUCCESS' : 'FAILED'));

            if (!$verified) {
                error_log("AuthenticateAdminUserService::authenticateRootUser: Password verification failed");
                try {
                    Log::Warning('AuthenticateAdminUserService: Root user password verification failed');
                } catch (Throwable $e) {
                    // Ignore logging errors
                }
                return new AuthenticationResult(false, message: 'Невірний логін або пароль');
            }

            // Root пользователь имеет специальный ID = 0 (не конфликтует с БД, где ID начинается с 1)
            error_log("AuthenticateAdminUserService::authenticateRootUser: Root user authenticated successfully. Returning userId: 0");
            try {
                Log::Info('AuthenticateAdminUserService: Root user authenticated successfully');
            } catch (Throwable $e) {
                // Ignore logging errors
            }

            return new AuthenticationResult(true, userId: 0);
        } catch (Throwable $e) {
            error_log("AuthenticateAdminUserService::authenticateRootUser: Exception: " . $e->getMessage() . " | File: " . $e->getFile() . " | Line: " . $e->getLine() . " | Trace: " . $e->getTraceAsString());
            try {
                Log::Error('AuthenticateAdminUserService: Root user authentication error', [
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return new AuthenticationResult(false, message: 'Невірний логін або пароль');
        }
    }

    /**
     * Проверка прав доступа к админ-панели
     *
     * @param int $userId
     * @return bool
     */
    private function checkAdminAccess(int $userId): bool
    {
        error_log("AuthenticateAdminUserService::checkAdminAccess: Checking access for user_id: {$userId}");

        // Root пользователь (userId = 0) всегда имеет доступ
        if ($userId === 0) {
            error_log("AuthenticateAdminUserService::checkAdminAccess: Root user (userId=0), access GRANTED");
            return true;
        }

        // Все остальные пользователи (включая userId = 1) должны иметь право 'admin.access'

        // Если репозиторий ролей не доступен, НЕ разрешаем доступ - это ошибка конфигурации
        if ($this->roles === null) {
            error_log("AuthenticateAdminUserService::checkAdminAccess: RoleRepository is NULL, access DENIED");
            try {
                Log::Error('AuthenticateAdminUserService: RoleRepository not available, denying access', [
                    'user_id' => $userId,
                ]);
            } catch (Throwable $e) {
                // Ignore logging errors
            }
            return false; // Изменено: не разрешаем доступ, если репозиторий недоступен
        }

        // Проверяем право 'admin.access'
        try {
            error_log("AuthenticateAdminUserService::checkAdminAccess: Calling roles->userHasPermission({$userId}, 'admin.access')");
            $hasPermission = $this->roles->userHasPermission($userId, 'admin.access');
            error_log("AuthenticateAdminUserService::checkAdminAccess: Permission check result: " . ($hasPermission ? 'GRANTED' : 'DENIED'));
            return $hasPermission;
        } catch (Throwable $e) {
            error_log("AuthenticateAdminUserService::checkAdminAccess: Exception during permission check: " . $e->getMessage());
            try {
                Log::Error('AuthenticateAdminUserService: Error checking admin access', [
                    'user_id' => $userId,
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            // В случае ошибки НЕ разрешаем доступ - это ошибка системы
            return false; // Изменено: не разрешаем доступ при ошибке
        }
    }
}
