<?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\ApplicationSystem;

use Ferienpass\AdminBundle\Event\ParticipantListEvent;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class ParticipantListDto
{
    public function __construct(private readonly EventDispatcherInterface $dispatcher, private readonly AuthorizationCheckerInterface $authorizationChecker)
    {
    }

    /**
     * @return array<string, string> where key is the table column and value is a twig equivalent of the cell value
     */
    public function adminViewColumns(OfferInterface $offer, Request $request): array
    {
        // The participant, attendance and payment drawers all live in
        // ParticipantsController, behind ROLE_PARTICIPANTS_ADMIN. A
        // Veranstalter holds that role no more than ROLE_ADMIN does (only
        // ROLE_SUPER_ADMIN inherits it), so a linked cell buys them nothing but
        // a slideover that 403s and stays empty. Mirror the controller's guard
        // and render the bare cell instead — no anchor, and none of the hover
        // affordance that advertises a target the user cannot reach.
        //
        // The consent drawer is deliberately NOT gated here: ConsentStateVoter
        // grants it to whoever may view the participants it belongs to, which
        // is everyone this list renders for.
        $linkParticipants = $this->authorizationChecker->isGranted('ROLE_PARTICIPANTS_ADMIN');

        if ('slideover' === $request->headers->get('turbo-frame')) {
            return [
                'name' => $this->nameCell($linkParticipants),
                // language=twig
                'age' => '
{% if not item.offer or not item.offer.dates|first or not item.offer.dates|first.begin %}
    {{ item.participant ? item.participant.age : "-" }}
{% else %}
    {{ item.participant ? item.participant.age(item.offer.dates|first.begin) : "-" }}
{% endif %}',
                'status' => $this->statusCell($linkParticipants),
                'consents' => $this->consentsCell(),
            ];
        }

        $columns = [
            'name' => $this->nameCell($linkParticipants),
            // language=twig
            'age' => '
{% if not item.offer or not item.offer.dates|first or not item.offer.dates|first.begin %}
    {{ item.participant ? item.participant.age : "-" }}
{% else %}
    {{ item.participant ? item.participant.age(item.offer.dates|first.begin) : "-" }}
{% endif %}',
            // language=twig
            'email' => '{{ item.participant ? item.participant.email : "-" }}',
            // language=twig
            'mobile' => '{{ item.participant ? item.participant.mobile : "-" }}',
            // language=twig
            'phone' => '{{ item.participant ? item.participant.phone : "-" }}',
            'status' => $this->statusCell($linkParticipants).'
{% if item.status == "withdrawn" and item.statusChangedAt %}<span class="ml-1 text-xs text-gray-500 dark:text-gray-400">{{ item.statusChangedAt|date("d.m.Y") }}</span>{% endif %}
{% if item.status == "unfulfilled" and item.decisionReason and is_granted("assign", item.offer.edition) %}<span class="ml-1 text-xs text-gray-500 dark:text-gray-400" title="{{ "Ausschlussgrund (nur für Verwaltung sichtbar)" }}">{{ ("decisionReason." ~ item.decisionReason)|trans({}, "admin") }}</span>{% endif %}',
            'paid' => $this->paidCell($linkParticipants),
            'consents' => $this->consentsCell(),
        ];

        if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) {
            // Payment/confirmation status is administrative information; hosts must not see it.
            unset($columns['paid']);
        }

        if (false === $offer->getEdition()?->usePayments()) {
            // The season doesn't collect fees, so there is no pay status to show.
            unset($columns['paid']);
        }

        $event = new ParticipantListEvent($offer, $columns);
        $this->dispatcher->dispatch($event);

        return $event->getColumns();
    }

    private function nameCell(bool $linked): string
    {
        // language=twig
        $label = '{{ item.participant ? item.participant.name : "Gelöschter Teilnehmer" }}';

        if (!$linked) {
            // The link's padding is cancelled by an equal negative margin, so
            // dropping it leaves the name in exactly the same place.
            return '<span class="font-medium text-gray-900 dark:text-gray-100">'.$label.'</span>';
        }

        // language=twig
        return '<a href="{{ path("admin_participants_show", { uuid: item.participant.uuid.toBase58 }) }}" class="hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100 rounded-md px-1.5 py-1 -mx-1.5 -my-1 font-medium text-gray-900 dark:text-gray-100 transition-colors" data-turbo-frame="slideover">'.$label.'</a>';
    }

    private function statusCell(bool $linked): string
    {
        // language=twig
        $badge = '<twig:Admin:Badge attendance="{{ item.status }}" size="sm" class="-ml-2" :dot="true" />';

        if (!$linked) {
            return "\n".$badge;
        }

        // language=twig
        return '
<a href="{{ path(\'admin_attendance_show\', { uuid: item.uuid.toBase58 }) }}" data-turbo-frame="slideover" class="hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md px-1 py-0.5 -mx-1 -my-0.5 transition-colors">
    '.$badge.'
</a>';
    }

    private function paidCell(bool $linked): string
    {
        // language=twig
        $body = '
{% if item.paid %}
    {% set payColor = "text-green-600" %}{% set payLabel = "bezahlt" %}
{% elseif item.stash %}
    {% set payColor = "text-gray-400" %}{% set payLabel = "unbestätigt" %}
{% elseif item.payable %}
    {% set payColor = "text-red-600" %}{% set payLabel = "unbezahlt" %}
{% else %}
    {% set payColor = "text-gray-400" %}{% set payLabel = "keine Zahllast" %}
{% endif %}
<span class="-ml-2 inline-flex items-center gap-x-1 align-middle">{{ ux_icon("ph:money-wavy", { class: "size-4 shrink-0 " ~ payColor }) }}<span class="font-medium text-gray-700 dark:text-gray-200">{{ payLabel }}</span></span>';

        if (!$linked) {
            return $body;
        }

        // language=twig
        return '
<a href="{{ path("admin_participants_attendances_payments", { uuid: item.uuid.toBase58 }) }}" data-turbo-frame="slideover" class="hover:bg-gray-100 dark:hover:bg-gray-800 rounded-md px-1 py-0.5 -mx-1 -my-0.5 transition-colors">'.$body.'
</a>';
    }

    private function consentsCell(): string
    {
        // language=twig
        return '
<div class="flex flex-col gap-y-1">
    {% if item.participant %}
        {% for state in consent_states(item) %}
            <a href="{{ path("admin_consents_details", { form: state.consentForm.id, user: item.participant.user.id, participant: (state.participant ? state.participant.uuid : null), token: item.consentToken }) }}" data-turbo-frame="slideover" class="inline-flex items-center gap-x-1.5 text-xs text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100 rounded-md px-1.5 py-1 -mx-1.5 -my-1 transition-colors" title="{{ state.title }}">
                <twig:Admin:ConsentStatusIcon :state="state" />
                <span class="truncate">{{ state.title }}</span>
            </a>
        {% endfor %}
    {% endif %}
</div>';
    }
}
