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

use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\PageModel;
use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\Section\SectionComponentInterface;
use Ferienpass\CoreBundle\Entity\Edition;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveArg;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentToolsTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

/**
 * "CMS integration" section of the Saison-Bearbeiten screen.
 *
 * Lets an admin surface the edition's public /o/{alias} landing page in
 * the frontend main navigation (positioned after a chosen Contao page)
 * and maintain an optional markdown intro rendered above the offer list.
 *
 * Storage lives on the {@see Edition} entity (addToNavigation /
 * navigationPositionAfter / welcomeText). The actual nav item is injected
 * at render time by the cms-bundle FrontendMenuEvent listener.
 */
#[AsLiveComponent('Admin:Edition:CmsIntegration', template: '@FerienpassAdmin/components/Edition/CmsIntegration.html.twig', route: 'live_component_admin')]
class CmsIntegration extends AbstractController implements SectionComponentInterface
{
    use ComponentToolsTrait;
    use DefaultActionTrait;

    #[LiveProp]
    public Edition $edition;

    #[LiveProp(writable: true, onUpdated: 'setDirty')]
    public bool $addToNavigation = false;

    #[LiveProp(writable: true, onUpdated: 'setDirty')]
    public ?int $navigationPositionAfter = null;

    #[LiveProp(writable: true, onUpdated: 'setDirty')]
    public ?string $welcomeText = null;

    #[LiveProp]
    public bool $isDirty = false;

    #[LiveProp]
    public array $sections = [];

    #[LiveProp]
    public ?string $section = null;

    public string $message = '';

    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly ContaoFramework $framework,
    ) {
    }

    public function mount(Edition $edition): void
    {
        $this->edition = $edition;
        $this->addToNavigation = $edition->isAddToNavigation();
        $this->navigationPositionAfter = $edition->getNavigationPositionAfter();
        $this->welcomeText = $edition->getWelcomeText();
    }

    public static function getSectionName(): string
    {
        return 'cms';
    }

    public static function getSectionScope(): string
    {
        return 'edition';
    }

    public function setDirty(): void
    {
        $this->isDirty = true;
    }

    /**
     * Flat list of navigable Contao pages for the "position after" picker,
     * keyed by page id → indented title. Root and error pages are skipped
     * (you can't sit a sibling next to a site root). Indentation mirrors
     * the page tree depth so the dropdown reads like the page navigator.
     *
     * @return array<int, string>
     */
    public function getPages(): array
    {
        $this->framework->initialize();

        $pageAdapter = $this->framework->getAdapter(PageModel::class);
        $pages = $pageAdapter->findAll(['order' => 'sorting']);
        if (null === $pages) {
            return [];
        }

        $byId = [];
        foreach ($pages as $page) {
            if (\in_array($page->type, ['root', 'error_401', 'error_403', 'error_404', 'error_503'], true)) {
                continue;
            }
            $byId[(int) $page->id] = $page;
        }

        $choices = [];
        foreach ($byId as $id => $page) {
            $depth = 0;
            $pid = (int) $page->pid;
            while (isset($byId[$pid]) && $depth < 10) {
                ++$depth;
                $pid = (int) $byId[$pid]->pid;
            }

            $choices[$id] = str_repeat('— ', $depth).($page->title ?: $page->alias ?: ('#'.$id));
        }

        return $choices;
    }

    #[LiveAction]
    public function save(#[LiveArg] ?string $nextSection = null, #[LiveArg] ?string $redirect = null): ?Response
    {
        $this->denyAccessUnlessGranted('ROLE_ADMIN');

        $this->edition->setAddToNavigation($this->addToNavigation);
        $this->edition->setNavigationPositionAfter($this->addToNavigation ? $this->navigationPositionAfter : null);
        $this->edition->setWelcomeText('' !== trim((string) $this->welcomeText) ? $this->welcomeText : null);

        $this->entityManager->flush();

        $this->isDirty = false;

        if ($nextSection || $redirect) {
            $this->addFlash('success', ['type' => 'success', 'title' => 'Daten gespeichert', 'message' => 'Die Änderungen wurden erfolgreich übernommen.']);
        } else {
            $this->message = 'Die Änderungen wurden erfolgreich übernommen.';
        }

        $this->dispatchBrowserEvent('live:saved', ['success' => true]);

        if ($nextSection) {
            return $this->redirectToRoute('admin_editions_edit', ['alias' => $this->edition->getAlias(), 'section' => $nextSection]);
        }
        if ($redirect) {
            return $this->redirectToRoute($redirect, ['alias' => $this->edition->getAlias()]);
        }

        return null;
    }
}
