<?php declare(strict_types=1);

namespace App\Console\Commands;

use App\Dto\User\ManyRoleDto;
use App\Enums\SystemRole;
use App\Repositories\RoleRepository;
use App\Services\User\UserCommandHandler;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator as ValidatorFacade;
use Illuminate\Validation\Rules\Password;
use Illuminate\Validation\Validator;

final class CreateUserAdmin extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:create-user-admin {email} {password}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Create admin user.';

    /**
     * Execute the console command.
     */
    public function handle(UserCommandHandler $userCommandHandler, RoleRepository $roleRepository): void
    {
        $validator = $this->getData();

        if ($validator->fails()) {
            $this->errorMessageAndStop($validator->errors()->all());
        }
        $data = $validator->valid();

        try {
            $role = $roleRepository->getRoleByCode(SystemRole::Admin->value);
            if (is_null($role)) {
                $this->errorMessageAndStop('Administrator role not found.');
            }
            $user = DB::transaction(function () use($data, $userCommandHandler, $role) {
                $data['name'] = 'Administrator';
                $user = $userCommandHandler->handleStore($data, $data['password']);
                $userCommandHandler->handleConfirmationByEmail($user);
                $roles = new ManyRoleDto([$role->id]);
                $userCommandHandler->handleSyncRoles($user, $roles);

                return $user;
            });
        } catch (\Throwable $e) {
            $this->errorMessageAndStop($e->getMessage());
        }

        $this->info('The command was successful!');
    }

    private function getData(): Validator
    {
        return ValidatorFacade::make([
            'email' => $this->argument('email'),
            'password' => $this->argument('password'),
        ], [
            'email' => ['required', 'email', 'unique:users,email'],
            'password' => ['required', Password::default()],
        ]);
    }

    private function stop(): never
    {
        exit;
    }

    private function errorMessageAndStop(string | array $error): never
    {
        $this->info('User not created. See error messages below:');

        if (is_array($error)) {
            foreach ($error as $err) {
                $this->error($err);
            }
        } else {
            $this->error($error);
        }

        $this->stop();
    }
}