<?php

declare(strict_types=1);

namespace App\Controller;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[Route('/api/user')]
#[IsGranted('ROLE_USER')]
class UserApiController extends AbstractController
{
    private const VALID_THEMES = [
        'warm-craft',
        'playful-pop',
        'sage-cream',
        'dusty-mauve',
        'ocean-dusk',
        'honey-slate',
    ];

    private const VALID_DESIGN_VERSIONS = ['v1', 'v2'];
    public const DESIGN_COOKIE = 'wevisto_design';

    #[Route('/search', name: 'api_users_search', methods: ['GET'])]
    public function search(Request $request, EntityManagerInterface $em): JsonResponse
    {
        $q = trim((string) $request->query->get('q', ''));
        if (strlen($q) < 2) {
            return $this->json([]);
        }

        /** @var User $me */
        $me = $this->getUser();

        $results = $em->createQueryBuilder()
            ->select('u')
            ->from(User::class, 'u')
            ->where('u.email LIKE :q')
            ->andWhere('u.id != :me')
            ->setParameter('q', '%' . $q . '%')
            ->setParameter('me', $me->getId())
            ->setMaxResults(10)
            ->getQuery()
            ->getResult();

        return $this->json(array_map(
            static fn(User $u) => ['id' => $u->getId(), 'email' => $u->getEmail()],
            $results,
        ));
    }

    #[Route('/theme', name: 'api_user_theme', methods: ['PATCH'])]
    public function updateTheme(Request $request, EntityManagerInterface $em): JsonResponse
    {
        $body = json_decode($request->getContent(), true);
        $theme = $body['theme'] ?? null;

        if (!is_string($theme) || !in_array($theme, self::VALID_THEMES, true)) {
            return $this->json(['error' => 'Invalid theme'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        /** @var User $user */
        $user = $this->getUser();
        $user->setTheme($theme);
        $em->flush();

        return $this->json(['theme' => $theme]);
    }

    #[Route('/design', name: 'api_user_design', methods: ['PATCH'])]
    public function updateDesignVersion(Request $request, EntityManagerInterface $em): JsonResponse
    {
        $body    = json_decode($request->getContent(), true);
        $version = $body['designVersion'] ?? null;

        if (!is_string($version) || !in_array($version, self::VALID_DESIGN_VERSIONS, true)) {
            return $this->json(['error' => 'Invalid designVersion'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        /** @var User $user */
        $user = $this->getUser();
        $user->setDesignVersion($version);
        $em->flush();

        $response = $this->json(['designVersion' => $version]);
        // Cookie mirrors the server-side preference so Twig pages (login,
        // setup, help) can do correct first-paint without re-querying the DB.
        $response->headers->setCookie(Cookie::create(self::DESIGN_COOKIE, $version)
            ->withPath('/')
            ->withExpires(new \DateTimeImmutable('+1 year'))
            ->withHttpOnly(false)  // readable from JS so the SPA can swap design without reload
            ->withSameSite('Lax'));
        return $response;
    }

    #[Route('/password', name: 'api_user_password', methods: ['PATCH'])]
    public function updatePassword(
        Request $request,
        EntityManagerInterface $em,
        UserPasswordHasherInterface $hasher,
    ): JsonResponse {
        $body            = json_decode($request->getContent(), true);
        $currentPassword = $body['currentPassword'] ?? null;
        $newPassword     = $body['newPassword'] ?? null;

        if (!is_string($currentPassword) || !is_string($newPassword)) {
            return $this->json(['error' => 'Both currentPassword and newPassword are required'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }
        if (strlen($newPassword) < 8) {
            return $this->json(['error' => 'New password must be at least 8 characters'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        /** @var User $user */
        $user = $this->getUser();
        if (!$hasher->isPasswordValid($user, $currentPassword)) {
            return $this->json(['error' => 'Current password is incorrect'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $user->setPassword($hasher->hashPassword($user, $newPassword));
        $em->flush();

        return $this->json(null, Response::HTTP_NO_CONTENT);
    }

    #[Route('/timezone', name: 'api_user_timezone', methods: ['PATCH'])]
    public function updateTimezone(Request $request, EntityManagerInterface $em): JsonResponse
    {
        $body = json_decode($request->getContent(), true);
        $tz   = $body['timezone'] ?? null;

        if (!is_string($tz)) {
            return $this->json(['error' => 'Missing timezone'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        try {
            new \DateTimeZone($tz);
        } catch (\Exception) {
            return $this->json(['error' => 'Invalid timezone identifier'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        /** @var User $user */
        $user = $this->getUser();
        $user->setTimezone($tz);
        $em->flush();

        return $this->json(['timezone' => $tz]);
    }
}
