<?php

namespace apexl\Io\modules\user;

use apexl\Config\ConfigurationInterface;
use apexl\Config\Exceptions\MissingConfigException;
use apexl\Io\enums\HttpMethod;
use apexl\Io\includes\Controller;
use apexl\Io\includes\RouteManager;
use apexl\Io\modules\email\services\TemplateService;
use apexl\Io\modules\system\interfaces\ProvidesRoutesInterface;
use apexl\Io\modules\user\classes\userManagedApiModule;
use apexl\Io\modules\user\controllers\EndMasqueradeController;
use apexl\Io\modules\user\controllers\ForgotPasswordController;
use apexl\Io\modules\user\controllers\ForgotPasswordWithLinkController;
use apexl\Io\modules\user\controllers\LoginByKeyController;
use apexl\Io\modules\user\controllers\LoginController;
use apexl\Io\modules\user\controllers\LogoutController;
use apexl\Io\modules\user\controllers\RefreshController;
use apexl\Io\modules\user\controllers\RegisterController;
use apexl\Io\modules\user\controllers\ResetPasswordController;
use apexl\Io\modules\user\controllers\rolesController;
use apexl\Io\modules\user\controllers\StartMasqueradeController;
use apexl\Io\modules\user\entities\roleEntity;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Io\modules\user\enums\permissions\Role;
use apexl\Io\modules\user\enums\permissions\User;
use apexl\Io\modules\user\hooks\AddCreatedByToEntitiesOnSave;
use apexl\Io\modules\user\hooks\AddMasqueradingWarning;
use apexl\Io\modules\user\hooks\AddMiddleware;
use apexl\Io\modules\user\hooks\AddModifiedByToEntitiesOnSave;
use apexl\Io\modules\user\hooks\AddUserToGlobalPageData;
use apexl\Io\modules\user\hooks\ApplyPermissionChecksToEntityFindQuery;
use apexl\Io\modules\user\hooks\ConsoleCommands;
use apexl\Io\modules\user\hooks\HashRefreshTokenBeforeStore;
use apexl\Io\modules\user\hooks\HashUserPasswordBeforeStore;
use apexl\Io\modules\user\hooks\RegisterModulePermissions;
use apexl\Io\modules\user\hooks\RegisterRolePermissions;
use apexl\Io\modules\user\hooks\RegisterTemplateFolder;
use apexl\Io\modules\user\hooks\SendNewUserNotification;
use apexl\Io\modules\user\interfaces\ProvidesPermissionsInterface;
use apexl\Io\modules\user\services\Permissions;
use apexl\Io\services\InstallChecker;
use app\vendor\apexl\io\src\Io\interfaces\ProvidesHooksInterface;
use app\vendor\apexl\utils\src\Utils\Strings\Append;

/**
 * Base module file, provides required methods to register things like routes and middleware.
 * Class installModule
 * @package apexl\Io\modules\install
 */
class userModule extends userManagedApiModule implements
    ProvidesHooksInterface,
    ProvidesPermissionsInterface,
    ProvidesRoutesInterface
{
    public function __construct(
        private readonly TemplateService $templateService,
        InstallChecker $installChecker,
        ConfigurationInterface $config,
    ) {
        parent::__construct($installChecker, $config);
    }

    public static function moduleDir(string $append = ''): string
    {
        return Append::append(__DIR__, $append);
    }

    public function initialise(): void
    {
        parent::initialise();
        $this->templateService->locations->add(sprintf('%s/templates/email', __DIR__));
    }

    public function routes(RouteManager $routeManager): void
    {
        $this->addGlobalRoutes($routeManager);
        //@route VERB /api/v{VERSION}/user/user
        $this->addProtectedEntityRoutes($routeManager, userEntity::class, [
            'get' => [Controller::class . ':get', User::VIEW],
            'put' => [RegisterController::class, User::UPDATE_SELF],
            'delete' => [Controller::class . ':delete', User::DELETE],
        ]);

        //@route VERB /api/v{VERSION}/user/role
        $this->addProtectedEntityRoutes($routeManager, roleEntity::class, [
            'get' => [rolesController::class . ':getRoles', Role::VIEW],
            'put' => [rolesController::class . ':createUpdate', Role::CREATE],
            'post' => [rolesController::class . ':createUpdate', Role::CREATE],
            'delete' => [rolesController::class . ':delete', Role::DELETE],
        ]);
    }

    /**
     * @throws MissingConfigException
     */
    protected function addGlobalRoutes(RouteManager $routeManager)
    {
        //@route GET /api/v{VERSION}/user/actions/logout
        $this->addActionRoute(
            $routeManager,
            HttpMethod::GET,
            'user.logout',
            'logout',
            LogoutController::class,
        );

        $this->addProtectedActionRoute(
            $routeManager,
            HttpMethod::GET,
            'user.masquerade',
            'masquerade/{id}',
            StartMasqueradeController::class,
            User::CAN_MASQUERADE,
        );

        $this->addProtectedActionRoute(
            $routeManager,
            HttpMethod::GET,
            'user.masquerade.end',
            'end-masquerade',
            EndMasqueradeController::class,
        );

        $this->addProtectedActionRoute(
            $routeManager,
            HttpMethod::POST,
            'user.register',
            '/register',
            RegisterController::class,
            User::CAN_REGISTER,
        );

        //@route GET /api/v{VERSION}/user/actions/login
        $this->addActionRoute(
            $routeManager,
            HttpMethod::POST,
            'user.login',
            'login',
            LoginController::class,
        );

        if ($this->config->get('auth.enable_query_string_login')) {
            //@route GET /api/v{VERSION}/user/actions/login/nfc
            $this->addActionRoute(
                $routeManager,
                HttpMethod::POST,
                'user.login.nfc',
                'login/nfc',
                LoginByKeyController::class,
            );
        }
        //@route GET /api/v{VERSION}/user/actions/forgot-password
        $this->addActionRoute(
            $routeManager,
            HttpMethod::POST,
            'user.forgot-password',
            'forgot-password',
            ForgotPasswordController::class,
        );
        //@route GET /api/v{VERSION}/user/data/forgot-password/h/{hash}
        $this->addDataRoute(
            $routeManager,
            HttpMethod::GET,
            'user.forgot-password.hash',
            'forgot-password/h/{hash}',
            ForgotPasswordWithLinkController::class,
        );
        $this->addActionRoute(
            $routeManager,
            HttpMethod::POST,
            'user.refresh',
            'refresh',
            RefreshController::class
        );
        $this->addActionRoute(
            $routeManager,
            HttpMethod::POST,
            'user.resetPassword',
            'reset-password',
            ResetPasswordController::class,
        );
    }

    public function permissions(Permissions $permissions): void
    {
        $permissions->registerPermission(User::VIEW, 'View Users', 'Users');
        $permissions->registerPermission(User::CREATE, 'Create Users', 'Users');
        $permissions->registerPermission(User::UPDATE, 'Update Users', 'Users');
        $permissions->registerPermission(User::UPDATE_SELF, 'Update Self', 'Users');
        $permissions->registerPermission(User::CHANGE_ACTIVE_STATE, 'Change Active State', 'Users');
        $permissions->registerPermission(User::DELETE, 'Delete Users', 'Users');
        $permissions->registerPermission(User::CAN_REGISTER, 'Can Register (For Anon Users)', 'Users');
        $permissions->registerPermission(User::MANAGE, 'Manage All User Accounts');

        $permissions->registerPermission(Role::SET, 'Can Set User Roles', 'Users');
        $permissions->registerPermission(Role::VIEW, 'View Roles', 'Roles');
        $permissions->registerPermission(Role::CREATE, 'Create Roles', 'Roles');
        $permissions->registerPermission(Role::UPDATE, 'Update Roles', 'Roles');
        $permissions->registerPermission(Role::DELETE, 'Delete Roles', 'Roles');

    }

    public function hooks(): array
    {
        $hooks = [
            RegisterRolePermissions::class,
            SendNewUserNotification::class,
            RegisterModulePermissions::class,
            RegisterTemplateFolder::class,
            AddMiddleware::class,
            HashRefreshTokenBeforeStore::class,
            HashUserPasswordBeforeStore::class,
            AddCreatedByToEntitiesOnSave::class,
            AddModifiedByToEntitiesOnSave::class,
            ConsoleCommands::class,
        ];

        if (!defined('DAEDALUS') || !DAEDALUS) {
            $hooks[] = ApplyPermissionChecksToEntityFindQuery::class;
        }

        if (class_exists('apexl\\Io\\modules\\display\\includes\\Page')) {
            $hooks[] = AddUserToGlobalPageData::class;
            $hooks[] = AddMasqueradingWarning::class;
        }

        return $hooks;
    }
}
