<?php

namespace App\Modules\Auth\Services;

use App\Modules\Auth\Models\RoleModel;
use App\Modules\Auth\Models\UserModel;
use App\Modules\Auth\Models\UserRoleModel;

/**
 * Auth Service
 *
 * Login / logout / currentUser using PHP session.
 */
class AuthService
{
    public const SESSION_USER_ID = 'auth_user_id';

    protected UserModel $userModel;
    protected RoleModel $roleModel;
    protected UserRoleModel $userRoleModel;

    public function __construct()
    {
        $this->userModel     = new UserModel();
        $this->roleModel     = new RoleModel();
        $this->userRoleModel = new UserRoleModel();
    }

    /**
     * Login with email and password.
     *
     * @param string $email
     * @param string $password
     * @return array|null User data + roles, or null on failure
     */
    public function login(string $email, string $password): ?array
    {
        $user = $this->userModel->findByEmail($email);
        if (!$user || !$user->isActive()) {
            return null;
        }

        if (!password_verify($password, $user->password_hash)) {
            return null;
        }

        $session = session();
        $session->set(self::SESSION_USER_ID, $user->id);

        return $this->userWithRoles($user);
    }

    /**
     * Logout (destroy session auth data).
     */
    public function logout(): void
    {
        $session = session();
        $session->remove(self::SESSION_USER_ID);
    }

    /**
     * Get current logged-in user with roles, or null.
     *
     * @return array|null { id, name, email, roles: [ role_code, role_name ] }
     */
    public function currentUser(): ?array
    {
        $session = session();
        $rawUserId = $session->get(self::SESSION_USER_ID);
        $userId    = (int) $rawUserId;
        if ($userId <= 0) {
            return null;
        }

        $user = $this->userModel->find($userId);
        if (!$user || !$user->isActive()) {
            $session->remove(self::SESSION_USER_ID);
            return null;
        }

        return $this->userWithRoles($user);
    }

    /**
     * Change password for the given user. Verifies current password first.
     *
     * @param int    $userId
     * @param string $currentPassword
     * @param string $newPassword
     * @return bool True on success, false if current password wrong or user not found
     */
    public function changePassword(int $userId, string $currentPassword, string $newPassword): bool
    {
        $user = $this->userModel->find($userId);
        if (!$user || !$user->isActive()) {
            return false;
        }

        if (!password_verify($currentPassword, $user->password_hash)) {
            return false;
        }

        $hash = password_hash($newPassword, PASSWORD_DEFAULT);
        $this->userModel->update($userId, ['password_hash' => $hash]);

        return true;
    }

    /**
     * Build user array with roles (no password).
     */
    protected function userWithRoles($user): array
    {
        $roleIds = $this->userRoleModel->getRoleIdsForUser($user->id);
        $roles  = [];
        foreach ($roleIds as $roleId) {
            $role = $this->roleModel->find($roleId);
            if ($role) {
                $roles[] = [
                    'role_code' => $role->role_code,
                    'role_name' => $role->role_name,
                ];
            }
        }

        return [
            'id'    => $user->id,
            'name'  => $user->name,
            'email' => $user->email,
            'roles' => $roles,
        ];
    }
}
