<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Core\Auth;
use App\Core\Controller;
use App\Services\UtilisateurService;
use Throwable;

final class UtilisateurController extends Controller
{
    public function __construct(
        private readonly UtilisateurService $users =
            new UtilisateurService()
    ) {
    }

    public function index(): void
    {
        $this->view('utilisateurs/index', [
            'users' => $this->users->all(),
            'success' => $this->pullFlash('success'),
            'error' => $this->pullFlash('error'),
        ]);
    }

    public function create(): void
    {
        $this->view('utilisateurs/form', [
            'user' => null,
            'roles' => $this->users->roles(),
            'errors' => [],
            'old' => [],
            'isEdit' => false,
        ]);
    }

    public function store(): void
    {
        try {
            $userId = $this->users->create($_POST);

            $this->flash(
                'success',
                'L’utilisateur a été créé avec succès.'
            );

            $this->redirect(
                'utilisateurs_show&id=' . $userId
            );
        } catch (Throwable $exception) {
            $this->view('utilisateurs/form', [
                'user' => null,
                'roles' => $this->users->roles(),
                'errors' => [
                    'general' => $exception->getMessage(),
                ],
                'old' => $_POST,
                'isEdit' => false,
            ]);
        }
    }

    public function show(): void
    {
        try {
            $userId = $this->getId();
            $this->assertCanAccessProfile($userId);

            $this->view('utilisateurs/show', [
                'user' => $this->users->find($userId),
                'success' => $this->pullFlash('success'),
                'error' => $this->pullFlash('error'),
            ]);
        } catch (Throwable $exception) {
            $this->flash(
                'error',
                $exception->getMessage()
            );

            $this->redirect('utilisateurs');
        }
    }

    public function edit(): void
    {
        try {
            $userId = $this->getId();
            $user = $this->users->find($userId);

            $this->view('utilisateurs/form', [
                'user' => $user,
                'roles' => $this->users->roles(),
                'errors' => [],
                'old' => $user,
                'isEdit' => true,
            ]);
        } catch (Throwable $exception) {
            $this->flash(
                'error',
                $exception->getMessage()
            );

            $this->redirect('utilisateurs');
        }
    }

    public function update(): void
    {
        $userId = (int)($_POST['id'] ?? 0);

        try {
            $this->users->update(
                $userId,
                $_POST
            );

            $this->flash(
                'success',
                'L’utilisateur a été modifié avec succès.'
            );

            $this->redirect(
                'utilisateurs_show&id=' . $userId
            );
        } catch (Throwable $exception) {
            $user = null;

            try {
                $user = $this->users->find($userId);
            } catch (Throwable) {
                // L’erreur principale sera affichée.
            }

            $this->view('utilisateurs/form', [
                'user' => $user,
                'roles' => $this->users->roles(),
                'errors' => [
                    'general' => $exception->getMessage(),
                ],
                'old' => array_replace(
                    $user ?? [],
                    $_POST
                ),
                'isEdit' => true,
            ]);
        }
    }

    public function password(): void
    {
        try {
            $userId = $this->getId();
            $this->assertCanAccessProfile($userId);

            $this->view(
                'utilisateurs/password',
                [
                    'user' => $this->users->find($userId),
                    'errors' => [],
                ]
            );
        } catch (Throwable $exception) {
            $this->flash(
                'error',
                $exception->getMessage()
            );

            $this->redirect('utilisateurs');
        }
    }

    public function updatePassword(): void
    {
        $userId = (int)($_POST['id'] ?? 0);

        try {
            $this->assertCanAccessProfile($userId);

            $this->users->changePassword(
                $userId,
                (string)($_POST['password'] ?? ''),
                (string)(
                    $_POST['password_confirmation']
                    ?? ''
                )
            );

            $this->flash(
                'success',
                'Le mot de passe a été modifié avec succès.'
            );

            $this->redirect(
                'utilisateurs_show&id=' . $userId
            );
        } catch (Throwable $exception) {
            $user = null;

            try {
                $user = $this->users->find($userId);
            } catch (Throwable) {
                // L’erreur principale sera affichée.
            }

            $this->view(
                'utilisateurs/password',
                [
                    'user' => $user,
                    'errors' => [
                        'general' =>
                            $exception->getMessage(),
                    ],
                ]
            );
        }
    }

    public function deactivate(): void
    {
        $userId = (int)($_POST['id'] ?? 0);

        try {
            if (Auth::id() === $userId) {
                throw new \RuntimeException(
                    'Vous ne pouvez pas désactiver votre propre compte.'
                );
            }

            $this->users->deactivate($userId);

            $this->flash(
                'success',
                'L’utilisateur a été désactivé.'
            );
        } catch (Throwable $exception) {
            $this->flash(
                'error',
                $exception->getMessage()
            );
        }

        $this->redirect('utilisateurs');
    }

    private function assertCanAccessProfile(int $userId): void
    {
        if (Auth::hasRole('ADMINISTRATEUR') || Auth::id() === $userId) {
            return;
        }

        throw new \RuntimeException(
            'Vous ne pouvez accéder qu’à votre propre profil.'
        );
    }

    private function getId(): int
    {
        $id = (int)($_GET['id'] ?? 0);

        if ($id <= 0) {
            throw new \InvalidArgumentException(
                'Utilisateur invalide.'
            );
        }

        return $id;
    }

    private function flash(
        string $key,
        string $message
    ): void {
        $_SESSION['flash'][$key] = $message;
    }

    private function pullFlash(string $key): ?string
    {
        $message = $_SESSION['flash'][$key] ?? null;

        unset($_SESSION['flash'][$key]);

        return is_string($message)
            ? $message
            : null;
    }
}