<?php

declare(strict_types=1);

namespace App\Controller\Token;

use App\Entity\Device;
use App\Entity\SharedImage;
use App\Enum\DeviceModel;
use App\Enum\Orientation;
use App\Enum\SharedImageStatus;
use App\Enum\TokenType;
use App\Message\RenderImageMessage;
use App\Service\TokenService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;

class TokenActionController extends AbstractController
{
    public function __construct(
        private readonly TokenService           $tokenService,
        private readonly EntityManagerInterface $em,
        private readonly MessageBusInterface    $bus,
    ) {}

    #[Route('/token/{uuid}/approve', name: 'token_approve_show', methods: ['GET'])]
    public function approveShow(string $uuid): Response
    {
        $token = $this->tokenService->findValid($uuid, TokenType::ShareApprove);
        if (!$token) {
            return $this->render('token/invalid.html.twig', ['reason' => 'This approval link has expired or already been used.']);
        }

        $user    = $this->getUser();
        $devices = $user ? $this->em->getRepository(Device::class)->findBy(['user' => $user]) : [];

        return $this->render('token/approve.html.twig', [
            'token'   => $token,
            'devices' => $devices,
            'user'    => $user,
        ]);
    }

    #[Route('/token/{uuid}/approve', name: 'token_approve_submit', methods: ['POST'])]
    public function approveSubmit(string $uuid, Request $request): Response
    {
        $token = $this->tokenService->findValid($uuid, TokenType::ShareApprove);
        if (!$token) {
            return $this->render('token/invalid.html.twig', ['reason' => 'This approval link has expired or already been used.']);
        }

        $user = $this->getUser();
        if (!$user) {
            return $this->redirectToRoute('app_login');
        }

        $deviceIds = $request->request->all('device_ids');
        $image     = $token->getImage();

        foreach ($deviceIds as $deviceId) {
            $device = $this->em->getRepository(Device::class)->findOneBy(['id' => (int) $deviceId, 'user' => $user]);
            if (!$device) {
                continue;
            }
            $image->approveForDevice($device);
        }

        foreach (DeviceModel::cases() as $model) {
            foreach (Orientation::cases() as $orientation) {
                $this->bus->dispatch(new RenderImageMessage($image->getId(), $model->value, $orientation->value));
            }
        }

        $shared = $this->em->getRepository(SharedImage::class)->findOneBy([
            'sourceImage'   => $image,
            'recipientUser' => $user,
        ]);
        if ($shared) {
            $shared->setStatus(SharedImageStatus::Approved);
        }

        $this->tokenService->consume($uuid, TokenType::ShareApprove);
        $this->em->flush();

        return $this->render('token/approved.html.twig', ['image' => $image]);
    }

    #[Route('/token/{uuid}/decline', name: 'token_decline_show', methods: ['GET'])]
    public function declineShow(string $uuid, Request $request): Response
    {
        $token = $this->tokenService->findValid($uuid, TokenType::ShareDecline);
        if (!$token) {
            return $this->render('token/invalid.html.twig', ['reason' => 'This decline link has expired or already been used.']);
        }

        return $this->render('token/decline.html.twig', [
            'token'       => $token,
            'approveUuid' => $request->query->get('back'),
        ]);
    }

    #[Route('/token/{uuid}/decline', name: 'token_decline_submit', methods: ['POST'])]
    public function declineSubmit(string $uuid): Response
    {
        $token = $this->tokenService->consume($uuid, TokenType::ShareDecline);

        $user = $this->getUser();
        if ($user) {
            $shared = $this->em->getRepository(SharedImage::class)->findOneBy([
                'sourceImage'   => $token->getImage(),
                'recipientUser' => $user,
            ]);
            if ($shared) {
                $shared->setStatus(SharedImageStatus::Declined);
                $this->em->flush();
            }
        }

        return $this->render('token/declined.html.twig');
    }
}
