<?php

namespace apexl\Io\modules\userDisplay\controllers;

use apexl\Io\exceptions\RecordNotFoundException;
use apexl\Io\includes\Controller;
use apexl\Io\includes\HookManager;
use apexl\Io\includes\RouteManager;
use apexl\Io\includes\System;
use apexl\Io\modules\display\components\BasicLink;
use apexl\Io\modules\display\components\ButtonBar;
use apexl\Io\modules\display\components\CardEntityFilteredDisplayTable;
use apexl\Io\modules\display\components\genericComponents;
use apexl\Io\modules\display\components\RowWrapper;
use apexl\Io\modules\display\services\Render;
use apexl\Io\modules\formbuilder\Components\FormKitField\CheckboxFormKitField;
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\services\CurrentUserFactory;
use apexl\Io\modules\userDisplay\components\dashboardTiles;
use apexl\Io\modules\userDisplay\components\roleEntityDisplayTile;
use apexl\Io\modules\userDisplay\components\userEntityDisplayTile;
use apexl\Io\modules\userDisplay\forms\forgottenPasswordForm;
use apexl\Io\modules\userDisplay\forms\loginForm;
use apexl\Io\services\Output;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

final readonly class userController extends Controller
{
    public function __construct(
        private Render $render,
        private RouteManager $routeManager,
        private CurrentUserFactory $currentUserFactory,
        Output $output,
    ) {
        parent::__construct($output);
    }

    public function userViewSingle(ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface
    {
        $rowWrapper = new RowWrapper()->addClass('manageForm-wrapper');
        $rowWrapper->addComponent(dashboardTiles::userViewTile($args['id']));

        $userEntity = new userEntity();
        $userEntity->load($args['id']);

        $buttonsBar = new ButtonBar();
        $buttonsBar->setEntity($userEntity);

        $this->render->setPageTitle('Viewing [' . $userEntity->id . '] - ' . $userEntity->getNiceName());

        return $this->json($response, $this->render->build([$buttonsBar, $rowWrapper]));
    }

    /**
     * @throws RecordNotFoundException
     */
    public function userSettingsPage(HookManager $hookManager, ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $form = $this->userEditForm($hookManager, ['id' => $this->currentUserFactory->get()->id]);

        $this->render->setPageTitle('User Settings');

        return $this->json($response, $this->render->build([$form]));
    }


    /**
     * @throws RecordNotFoundException
     */
    public function userEditForm(HookManager $hookManager, array $args = []): Form
    {


        //set form field values
        $user = new userEntity();
        if (isset($args[$user->primaryKey])) {
            $user->load($args[$user->primaryKey]);
        }

        $form = $this->primaryAccountForm(false, $user);
        $form->setSubmitText('Submit');
        if (isset($args[$user->primaryKey])) {
            $form->setMethod('PUT');
        }

        $form->setActionUrl($this->routeManager->getRoutePattern('userEntity.put'));

        if ($this->currentUserFactory->get()->isAllowed(User::CHANGE_ACTIVE_STATE)) {
            $activeField = new CheckboxFormKitField('active')->setLabel('Active')->setValue($user->active ?? 0);
        } else {
            $activeField = new InputField('active')->setInputType('hidden')->setValue($user->active ?? 0);
        }

        if ($id = $args[$user->primaryKey] ?? false) {
            $form->setActionUrl($this->routeManager->getRoutePattern($user->getEntityName() . '.put', ['id' => $id]));
        }

        $form->addField($activeField);

        $form->setFieldsetSetting('roles', 'fieldset_legend', 'Roles');
        $roles = new roleEntity()->loadMultiple();
        foreach ($roles as $role) {
            //for users that can't change roles, show labels for those that they do have.
            $showLabel = false;
            if ($this->currentUserFactory->get()->isAllowed(Role::UPDATE)) {
                $roleField = new CheckboxFormKitField('role_' . $role->id)
                    ->setLabel($role->name)
                    ->setValue($user->hasRole($role));
            } else {
                $showLabel = true;
                $roleField = (new InputField('role_' . $role->id));
                $roleField->setInputType('hidden');
            }
            if (($user->id ?? false) && $user->hasRole($role)) {
                //allows us to show the label only for those without the role to change.
                //Only shows labels for the roles they have.
                if ($showLabel) {
                    $roleField->setLabel($role->name);
                }
            }
            $form->addField($roleField, 'roles');
        }

        //allow other modules to modify form.
        return $hookManager->processHook('displayFormRender', $form, $user, 'userEditForm');
    }

    /**
     * @param bool $passwordRequired
     */
    protected function primaryAccountForm($passwordRequired = false, $user = null): Form
    {
        $form = new Form();
        $form->setMethod('post');
        $form->setActionUrl($this->routeManager->getRoutePattern('userEntity.post'));

        $form->addField(
            new InputField('first_name')->setLabel('First Name')->setPlaceholder('First Name')->isRequired()->setValue(
                isset($user->first_name) ? $user->first_name : ''
            )
        );
        $form->addField(
            new InputField('last_name')->setLabel('Surname')->setPlaceholder('Surname')->isRequired()->setValue(
                isset($user->last_name) ? $user->last_name : ''
            )
        );
        $form->addField(
            new InputField('email')->setLabel('Email')->setPlaceholder('Email')->setInputType('email')->isRequired(
            )->setValue(isset($user->email) ? $user->email : '')
        );

        $password = new InputField('password')->setLabel('Password')->setPlaceholder('Password')->setInputType(
            'password'
        )->addValidation("minLength", ["min" => 6]);
        $confirmPass = new InputField('confirm_password')->setLabel('Confirm Password')->setPlaceholder(
            'Confirm Password'
        )->setInputType('password')->addValidation("minLength", ["min" => 6]);
        if ($passwordRequired) {
            $password->isRequired();
            $confirmPass->isRequired();
        }
        $form->addField($password);
        $form->addField($confirmPass);

        return $form;
    }

    public function create(HookManager $hookManager, ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface
    {
        $title = 'Create new user';
        if ($id = $args['id'] ?? false) {
            $user = new userEntity();
            $user->load($id);
            $title = 'Update ' . $user->getNiceName();
        }

        $form = $this->userEditForm($hookManager, $args);
        $this->render->setPageTitle($title);
        $this->output->addResponse($request, $this->render->build([genericComponents::dashboardBlockWrapper([$form])]));

        return $this->json($response);
    }

    public function registerPage(ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface
    {
        if ($this->redirectIfLoggedIn($response)) {
            return $this->json($response);
        }

        $this->render->setActive("noUI");
        $this->render->setPageTitle("Register");
        $components = [];

        $components[] = new FormComponent()->src($this->routeManager->getRoutePattern('user.display.forms.register'))
            ->title(System::getVariable('user_register_description_text') ?? "Register an account.")
            ->addClass('register-form')->setID('register');
        $components[] = new BasicLink()
            ->addClass('loginLink')
            ->addRoute($this->routeManager->getRoutePattern('user.display.login'))
            ->addText(System::getVariable('user_register_login_text') ?? 'Got an account? Log in.');

        return $this->json($response, $this->render->build($components));
    }

    protected function redirectIfLoggedIn(ResponseInterface $response): bool
    {
        if ($this->currentUserFactory->get()->isLoggedIn()) {
            $this->output->addMetadata('user.login.redirect', 'redirect', '/');
            return true;
        }
        return false;
    }

    /**
     * @return ResponseInterface
     */
    public function loginForm(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        return $this->json($response, new loginForm()->loginForm($request));
    }


    /**
     * @return ResponseInterface
     */
    public function forgotPasswordForm(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        return $this->json($response, new forgottenPasswordForm()->forgottenPasswordForm());
    }

    /**
     * @return ResponseInterface
     */
    public function registerForm(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $form = $this->primaryAccountForm(true);

        return $this->json($response, $form->getBuiltFormArray());
    }

    /**
     * @return ResponseInterface
     */
    public function userHome(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        $rowWrapper = new RowWrapper()->setColWidth('sm', 12)->addClass('manageForm-wrapper');
        $rowWrapper->setColWidth('sm', 12)->addClass('manageForm-wrapper');
        $rowWrapper->addComponent(new userEntityDisplayTile());
        if ($this->currentUserFactory->get()?->isAllowed(Role::VIEW)) {
            $rowWrapper->addComponent(new roleEntityDisplayTile());
        }

        $this->render->setPageTitle('User Dashboard');
        $this->output->addResponse($request, $this->render->build([$rowWrapper]));

        return $this->json($response);
    }

    /**
     * @return ResponseInterface
     * @throws \Exception
     */
    public function userList(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
    {
        //$filterForm = (new EntityFilteredDisplayTable((new userEntity()), [], false))->addEditButton('userEntity.display.put');
        //$filterForm->addFilterForm('user.display.forms.filters.userFilter');

        $components = [];

        $currentUser = $this->currentUserFactory->get();
        if ($currentUser && ($currentUser->isAllowed(User::CREATE))) {
            $createButton = new BasicLink()
                ->addText('Create User')
                ->addRoute($this->routeManager->getRoutePattern('userEntity.display.post'))
                ->addClass('btn btn-primary');
            $components[] = $createButton;
        }

        $components[] = new CardEntityFilteredDisplayTable(new userEntity(), [], false, 'dropmenu')
            ->displayPagination(FALSE)
            ->displayShortTotals(FALSE)
            ->hideIdColumn()
            ->addDropMenuItem('userEntity.display.put', 'Edit')
            ->addTitle('User List');

        //render
        $this->render->setPageTitle('User List');
        $this->output->addResponse($request, $this->render->build($components));

        return $this->json($response);
    }

    /**
     * @param array $args
     * @return ResponseInterface
     * @throws \Exception
     */
    public function updateView(HookManager $hookManager, ServerRequestInterface $request, ResponseInterface $response, array $args = []): ResponseInterface
    {
        $title = 'Create a user';
        if ($id = $args['id'] ?? false) {
            $userEntity = new userEntity();
            $userEntity->load($id);
            $title = 'Edit (' . $id . ') ' . $userEntity->getNiceName();
        }

        $form = $this->userEditForm($hookManager, $args);
        $this->render->setPageTitle($title);
        $this->output->addResponse($request, $this->render->build([$form]));

        return $this->json($response);
    }


    public function resetPasswordForm(ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface
    {
        $form = new formEntity();
        $form->setSubmitText('Reset Password Now');
        $form->setMethod('post');
        $form->setActionUrl($this->routeManager->getRoutePattern('user.resetPassword'));
        $form->addField(
            new InputField('password')->setLabel('Password')->setPlaceholder('Password')->setInputType(
                'password'
            )->addValidation("minLength", ["min" => 6])->isRequired()
        );
        $form->addField(
            new InputField('confirm_password')->setLabel('Confirm Password')->setPlaceholder(
                'Confirm Password'
            )->setInputType('password')->addValidation("minLength", ["min" => 6])->isRequired()
        );
        $form->addField(new InputField('hash')->setInputType('hidden')->setValue($args['hash'])->isRequired());

        return $this->json($response, $form->getBuiltFormArray());
    }

    /**
     * @param $args
     * @return ResponseInterface
     */
    public function userSummery(ServerRequestInterface $request, ResponseInterface $response, $args): ResponseInterface
    {
        $structure = [
            'tableHeader' => [
                'User ID',
                'Name',
                'Active',
                'Email',
                'Last Logged In',
                'Roles',
            ],
            'fields' => [
                'id',
                'first_name',
                'active',
                'email',
                'last_login',
                'roles',
            ],
            'callables' => [
                'field__last_login' => function ($key, $entityId, $row): string {
                    return \apexl\Io\modules\userDisplay\callbacks\tableRowAlters::userShortTable(
                        $key,
                        $entityId,
                        $row
                    );
                },
                'field__first_name' => function ($key, $entityId, $row): string {
                    return \apexl\Io\modules\userDisplay\callbacks\tableRowAlters::userShortTable(
                        $key,
                        $entityId,
                        $row
                    );
                },
                'field__roles' => function ($key, $entityId, $row): string {
                    return \apexl\Io\modules\userDisplay\callbacks\tableRowAlters::userShortTable(
                        $key,
                        $entityId,
                        $row
                    );
                },
            ],
        ];

        return $this->getEntityData($request, $response, $args, (new userEntity()), [], $structure);
    }
}
