<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\AdminBundle\Components;

use Ferienpass\CoreBundle\Application\ExtraFileManager;
use Ferienpass\CoreBundle\Application\ExtraFileRejected;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\AttendanceExtraFile;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait;

/**
 * The drawer behind a file answer in the participant list: it previews the
 * uploaded photo/PDF, hands it out as a download, and lets the team replace or
 * remove it — one place for all of it, the way the media file drawer works.
 *
 * Replacing exists because these files come from families: a photo is blurred, a
 * certificate is the wrong page, someone uploaded it upside down. The team can fix
 * that on the phone with the parent instead of sending them back to the form.
 *
 * Viewing follows the participant list (`participants.view`, checked by the
 * controller that renders this); writing needs `participants.edit`.
 */
#[AsLiveComponent(route: 'live_component_admin')]
class AttendanceFile extends AbstractController
{
    use DefaultActionTrait;

    #[LiveProp]
    public Attendance $attendance;

    /**
     * The extra question this file answers, `{uuid, question, type, required,
     * fileTypes}` as resolved (and validated against the offer) by
     * {@see \Ferienpass\AdminBundle\Controller\AttendanceExtraFileController}.
     */
    #[LiveProp]
    public array $question = [];

    /** Upload error for this request, `{key, params}` in the `admin` domain. */
    public ?array $error = null;

    public function __construct(private readonly ExtraFileManager $files)
    {
    }

    public function getFile(): ?AttendanceExtraFile
    {
        return $this->attendance->getExtraFile($this->questionUuid());
    }

    public function canEdit(): bool
    {
        return $this->isGranted('participants.edit', $this->attendance->getOffer());
    }

    #[LiveAction]
    public function upload(Request $request): void
    {
        $this->denyAccessUnlessGranted('participants.edit', $this->attendance->getOffer());

        $file = $request->files->get('extraFile');
        if (!$file instanceof UploadedFile) {
            return;
        }

        try {
            $this->files->replace($this->attendance, $this->questionUuid(), $file, $this->question['fileTypes'] ?? []);
        } catch (ExtraFileRejected $e) {
            // The keys live in the `cms` domain (the applicant-facing form raises
            // the same errors); reuse them rather than duplicating the copy.
            $this->error = ['key' => $e->getTranslationKey(), 'params' => $e->getParameters()];
        }
    }

    #[LiveAction]
    public function delete(): void
    {
        $this->denyAccessUnlessGranted('participants.edit', $this->attendance->getOffer());

        $file = $this->getFile();
        if ($file instanceof AttendanceExtraFile) {
            $this->files->delete($file);
        }
    }

    private function questionUuid(): string
    {
        return (string) ($this->question['uuid'] ?? '');
    }
}
