<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\Profile;
use App\Repository\ProfileRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;

use function count;
use function in_array;

#[Route('/api/admin/profiles')]
final class AdminProfileController extends AbstractController
{
    public function __construct(
        private readonly ProfileRepository $profiles,
        private readonly EntityManagerInterface $entityManager,
        private readonly UserPasswordHasherInterface $passwordHasher,
    ) {}

    #[Route('', name: 'admin_profiles_list', methods: ['GET'])]
    public function list(): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $items = $this->profiles->findBy([], ['firstName' => 'ASC']);

        return new JsonResponse(array_map([$this, 'serializeProfile'], $items));
    }

    #[Route('', name: 'admin_profiles_create', methods: ['POST'])]
    public function create(Request $request): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $payload   = $request->toArray();
        $firstName = trim((string) ($payload['firstName'] ?? ''));
        $lastName  = trim((string) ($payload['lastName'] ?? ''));

        if ('' === $firstName || '' === $lastName) {
            return new JsonResponse(['message' => 'firstName et lastName sont requis.'], JsonResponse::HTTP_BAD_REQUEST);
        }

        $email    = trim((string) ($payload['email'] ?? ''));
        $password = $payload['password'] ?? null;
        $role     = $payload['role'] ?? 'ROLE_VIEWER';

        $allowedRoles = ['ROLE_ADMIN', 'ROLE_GESTIONNAIRE', 'ROLE_VIEWER', 'ROLE_USER'];
        if (!in_array($role, $allowedRoles, true)) {
            return new JsonResponse(['message' => 'Role invalide.'], JsonResponse::HTTP_BAD_REQUEST);
        }

        $profile = new Profile();
        $profile->setFirstName($firstName);
        $profile->setLastName($lastName);
        $profile->setIsActive(true);
        $profile->setRoles([$role]);

        if ('' !== $email) {
            $profile->setEmail($email);
        }

        if (null !== $password && '' !== $password) {
            if (mb_strlen($password) < 8) {
                return new JsonResponse(['message' => 'Le mot de passe doit contenir au moins 8 caractères.'], JsonResponse::HTTP_BAD_REQUEST);
            }
            $profile->setPassword(
                $this->passwordHasher->hashPassword($profile, $password)
            );
        }

        $this->entityManager->persist($profile);
        $this->entityManager->flush();

        return new JsonResponse($this->serializeProfile($profile), JsonResponse::HTTP_CREATED);
    }

    #[Route('/{id}/role', name: 'admin_profiles_update_role', methods: ['PUT'])]
    public function updateRole(string $id, Request $request): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $profile = $this->profiles->find($id);
        if (!$profile) {
            return new JsonResponse(['message' => 'Profil introuvable.'], JsonResponse::HTTP_NOT_FOUND);
        }

        $payload = $request->toArray();
        $role    = $payload['role'] ?? null;

        $allowedRoles = ['ROLE_ADMIN', 'ROLE_GESTIONNAIRE', 'ROLE_VIEWER', 'ROLE_USER'];
        if (!$role || !in_array($role, $allowedRoles, true)) {
            return new JsonResponse(['message' => 'Role invalide.'], JsonResponse::HTTP_BAD_REQUEST);
        }

        // Prevent removing the last admin
        if (in_array('ROLE_ADMIN', $profile->getRoles(), true) && 'ROLE_ADMIN' !== $role) {
            $adminCount = $this->countAdmins();
            if ($adminCount <= 1) {
                return new JsonResponse(
                    ['message' => 'Impossible de retirer le dernier administrateur.'],
                    JsonResponse::HTTP_CONFLICT
                );
            }
        }

        $profile->setRoles([$role]);
        $this->entityManager->flush();

        return new JsonResponse($this->serializeProfile($profile));
    }

    #[Route('/{id}/password', name: 'admin_profiles_update_password', methods: ['PUT'])]
    public function updatePassword(string $id, Request $request): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $profile = $this->profiles->find($id);
        if (!$profile) {
            return new JsonResponse(['message' => 'Profil introuvable.'], JsonResponse::HTTP_NOT_FOUND);
        }

        $payload  = $request->toArray();
        $password = $payload['password'] ?? '';

        if ('' === $password) {
            return new JsonResponse(['message' => 'Le mot de passe est requis.'], JsonResponse::HTTP_BAD_REQUEST);
        }

        if (mb_strlen($password) < 8) {
            return new JsonResponse(['message' => 'Le mot de passe doit contenir au moins 8 caractères.'], JsonResponse::HTTP_BAD_REQUEST);
        }

        $profile->setPassword(
            $this->passwordHasher->hashPassword($profile, $password)
        );
        $this->entityManager->flush();

        return new JsonResponse($this->serializeProfile($profile));
    }

    #[Route('/{id}/deactivate', name: 'admin_profiles_deactivate', methods: ['PUT'])]
    public function deactivate(string $id): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $profile = $this->profiles->find($id);
        if (!$profile) {
            return new JsonResponse(['message' => 'Profil introuvable.'], JsonResponse::HTTP_NOT_FOUND);
        }

        // Prevent deactivating the last admin
        if (in_array('ROLE_ADMIN', $profile->getRoles(), true)) {
            $adminCount = $this->countAdmins();
            if ($adminCount <= 1) {
                return new JsonResponse(
                    ['message' => 'Impossible de desactiver le dernier administrateur.'],
                    JsonResponse::HTTP_CONFLICT
                );
            }
        }

        $profile->setIsActive(false);
        $this->entityManager->flush();

        return new JsonResponse($this->serializeProfile($profile));
    }

    private function serializeProfile(Profile $profile): array
    {
        return [
            'id'          => $profile->getId(),
            'firstName'   => $profile->getFirstName(),
            'lastName'    => $profile->getLastName(),
            'email'       => $profile->getEmail(),
            'isActive'    => $profile->isActive(),
            'hasPassword' => null !== $profile->getPassword() && '' !== $profile->getPassword(),
            'roles'       => $profile->getRoles(),
            'createdAt'   => $profile->getCreatedAt()->format('c'),
            'updatedAt'   => $profile->getUpdatedAt()->format('c'),
        ];
    }

    private function countAdmins(): int
    {
        $all = $this->profiles->findBy(['isActive' => true]);

        return count(array_filter(
            $all,
            static fn (Profile $p) => in_array('ROLE_ADMIN', $p->getRoles(), true)
        ));
    }
}
