<?php

declare(strict_types=1);

/*
 * This file is part of contao-weinanlieferung-bundle.
 *
 * (c) vonRotenberg
 *
 * @license commercial
 */

namespace vonRotenberg\WeinanlieferungBundle\Controller\Frontend\Module;

use Contao\Controller;
use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController;
use Contao\CoreBundle\Exception\ResponseException;
use Contao\CoreBundle\InsertTag\InsertTagParser;
use Contao\CoreBundle\ServiceAnnotation\FrontendModule;
use Contao\Date;
use Contao\FrontendUser;
use Contao\ModuleModel;
use Contao\PageModel;
use Contao\StringUtil;
use Contao\System;
use Contao\Template;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungReservationModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungSlotsModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungStandortModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungUnitsModel;

/**
 * @FrontendModule(WeinanlieferungSlotsListModuleController::TYPE, category="miscellaneous")
 */
class WeinanlieferungSlotsListModuleController extends AbstractFrontendModuleController
{
    public const TYPE = 'wa_slots_list';

    private $insertTagParser;

    private $db;

    public function __construct(InsertTagParser $insertTagParser, Connection $connection)
    {
        $this->insertTagParser = $insertTagParser;
        $this->db = $connection;
    }


    protected function getResponse(Template $template, ModuleModel $model, Request $request): ?Response
    {
        global $objPage;
        Controller::loadDataContainer('tl_vr_wa_slot');
        $GLOBALS['TL_CSS']['vr_wa'] = 'bundles/vonrotenbergweinanlieferung/css/frontend.scss|static';
        $standortIds = StringUtil::deserialize($model->vr_wa_standortId);
        $arrData = $template->getData();
        $arrOptions = [];

        // Add filter sql
        if (!empty($_GET['filter_kapazitaet']))
        {
            $filterRaw = (string) $_GET['filter_kapazitaet'];
            $arrData['filter']['kapazitaet']['selected'] = $filterRaw;

            // Support unit-prefixed values like "u1-16" (unit-specific) and legacy "u-16". Both resolve to numeric capacity 16 for SQL.
            $filterNumeric = null;
            $filterUnitId = null;
            if (preg_match('/^u(\d+)-(\d+)$/', $filterRaw, $m)) {
                // New format: u<unitId>-<capacity>
                $filterUnitId = (int) $m[1];
                $filterNumeric = (int) $m[2];
            } elseif (preg_match('/^u-(\d+)$/', $filterRaw, $m)) {
                // Legacy format kept for backward compatibility: u-<capacity>
                $filterNumeric = (int) $m[1];
            } else {
                $filterNumeric = (int) $filterRaw;
            }

            // Capacity availability condition
            $arrOptions['column'][] = '(SELECT tl_vr_wa_slot.behaelter - IFNULL(SUM(tl_vr_wa_reservation.behaelter),0) FROM tl_vr_wa_reservation WHERE tl_vr_wa_reservation.pid = tl_vr_wa_slot.id) >= ?';
            $arrOptions['value'][] = $filterNumeric;

            // If a specific unit was selected (new format), restrict slots to Standorte that have this unit enabled
            if ($filterUnitId !== null) {
                // units is a serialized array, match serialized occurrence of the unit id
                $arrOptions['column'][] = 'pid IN (SELECT id FROM tl_vr_wa_standort WHERE units REGEXP ?)';
                $arrOptions['value'][] = 's:[0-9]+:"' . $filterUnitId . '"';
            }
        }
        if (!empty($_GET['filter_standort']))
        {
            $arrData['filter']['standort']['selected'] = $_GET['filter_standort'];
            $arrOptions['column'][] = 'pid = ?';
            $arrOptions['value'][] = $_GET['filter_standort'];
        }
        if (!empty($_GET['filter_tag']) && ($Tag = new Date($_GET['filter_tag'])))
        {
            $arrData['filter']['tag']['selected'] = $_GET['filter_tag'];
            $arrOptions['column'][] = 'tl_vr_wa_slot.time BETWEEN ? and ?';
            $arrOptions['value'][] = $Tag->dayBegin;
            $arrOptions['value'][] = $Tag->dayEnd;
        }
        if (!empty($_GET['filter_ernteart']))
        {
            $arrData['filter']['ernteart']['selected'] = $_GET['filter_ernteart'];
            $arrOptions['column'][] = 'FIND_IN_SET (?,ernteart)';
            $arrOptions['value'][] = $_GET['filter_ernteart'];
        }
        if (!empty($_GET['filter_sorte']) && !empty($_GET['filter_leseart']))
        {
            $arrData['filter']['sorte']['selected'] = $_GET['filter_sorte'];
            $arrData['filter']['leseart']['selected'] = $_GET['filter_leseart'];
            $arrOptions['column'][] = "sorten REGEXP('\"sorte\";s:[0-9]+:\"" . intval($_GET['filter_sorte']) . "\"[^\}]+\"leseart\";s:[0-9]+:\"" . intval($_GET['filter_leseart']) . "\"')";
        } else {
            if (!empty($_GET['filter_sorte']))
            {
                $arrData['filter']['sorte']['selected'] = $_GET['filter_sorte'];
                $arrOptions['column'][] = "sorten REGEXP('\"sorte\";s:[0-9]+:\"" . intval($_GET['filter_sorte']) . "\"')";
            }
            if (!empty($_GET['filter_leseart']))
            {
                $arrData['filter']['leseart']['selected'] = $_GET['filter_leseart'];
                $arrOptions['column'][] = "sorten REGEXP('\"leseart\";s:[0-9]+:\"" . intval($_GET['filter_leseart']) . "\"')";
            }
        }

        // Get available slots
        if (($slots = WeinanlieferungSlotsModel::findMultiplePublishedByPids($standortIds,$arrOptions)) !== null)
        {
            $slotIds = $slots->fetchEach('id');

            /** @var WeinanlieferungSlotsModel $slot */
            foreach ($slots as $slot)
            {
                $day = new Date($slot->date);
                $arrSorten = [];
                $arrErnteart = [];
                $intAvailableBehaelter = max(0, $slot->getAvailableBehaelter());

                $Sorten = StringUtil::deserialize($slot->sorten, true);
                foreach ($Sorten as $sorte)
                {
                    $objSorte = WeinanlieferungRebsorteModel::findByPk($sorte['sorte']);
                    $objLeseart = WeinanlieferungLeseartModel::findByPk($sorte['leseart']);
                    $arrSorten[] = ($objSorte !== null ? $objSorte->title : '') . ' ' . ($objLeseart !== null ? $objLeseart->title : '');
                }

                if ($slot->ernteart !== null)
                {
                    foreach (explode(',', $slot->ernteart) as $ernteart)
                    {
                        $arrErnteart[] = $GLOBALS['TL_LANG']['REF']['wa_ernteart'][$ernteart] ?? $ernteart;
                    }
                }

                $strStandort = '';
                if (($Standort = $slot->getRelated('pid')) !== null)
                {
                    $strStandort = $Standort->title;
                }

                $arrLage = [];
                if (($Lage = $slot->getRelated('lage')) !== null)
                {
                    $arrLage = $Lage->fetchEach('title');
                }

                $arrData['days'][$day->dayBegin][] = array_merge($slot->row(), [
                    'anmerkungen'        => $slot->anmerkungen ? StringUtil::substr(strip_tags($slot->anmerkungen), 110) : '',
                    'standort'           => $strStandort,
                    'lage'               => $arrLage,
                    'sorte'              => $arrSorten,
                    'ernteart'           => $arrErnteart,
                    'behaelterAvailable' => $intAvailableBehaelter,
                    'buchbar'            => (boolean)$intAvailableBehaelter,
                    'gebucht'            => (boolean)WeinanlieferungReservationModel::countBy(["uid = ?", "pid = ?"], [FrontendUser::getInstance()->id, $slot->id])
                ]);
            }

            // Get filter values
            $result = $this->db->executeQuery("SELECT MAX(behaelter) as 'kapazitaet' FROM tl_vr_wa_slot WHERE id IN (" . implode(',', $slotIds) . ")");
            $intMaxKapazitaet = (int)$result->fetchOne();

            // Build capacity filter options as an ordered list where each item has a numeric value and a label.
            // Do not combine unit labels with numeric labels; append unit options at the bottom.
            $options = [];
            $max = max(1, $intMaxKapazitaet);

            // Plain numeric options first
            for ($i = 1; $i <= $max; $i++) {
                $options[] = [
                    'value' => (string) $i,
                    'label' => (string) $i,
                ];
            }

            // Determine which units are enabled on any of the shown standorts (locations)
            $allowedUnitIds = [];
            $shownStandortIds = [];
            if (!empty($slotIds)) {
                // Get unique Standort IDs from the shown slots
                $shownStandortIds = array_unique($slots->fetchEach('pid'));
                if (!empty($shownStandortIds)) {
                    if (($ShownStandorte = WeinanlieferungStandortModel::findBy(["id IN (" . implode(',', $shownStandortIds) . ")"],null)) !== null) {
                        foreach ($ShownStandorte as $ShownStandort) {
                            $ids = \Contao\StringUtil::deserialize($ShownStandort->units, true);
                            if (!empty($ids)) {
                                foreach ($ids as $uid) {
                                    $allowedUnitIds[(int)$uid] = true;
                                }
                            }
                        }
                    }
                }
            }

            // Build a map of units enabled per shown Standort and compute per-unit max available capacity across shown slots
            $unitsPerStandort = [];
            $unitMaxAvailable = [];
            if (!empty($shownStandortIds)) {
                if (($ShownStandorte = WeinanlieferungStandortModel::findBy(["id IN (" . implode(',', $shownStandortIds) . ")"], null)) !== null) {
                    foreach ($ShownStandorte as $ShownStandort) {
                        $sid = (int) $ShownStandort->id;
                        $ids = \Contao\StringUtil::deserialize($ShownStandort->units, true);
                        if (!empty($ids)) {
                            foreach ($ids as $uid) {
                                $uid = (int) $uid;
                                $unitsPerStandort[$sid][$uid] = true;
                                // initialize unit max availability bucket
                                if (!isset($unitMaxAvailable[$uid])) {
                                    $unitMaxAvailable[$uid] = 0;
                                }
                            }
                        }
                    }
                }
            }

            // Iterate the shown slots and, for each, update max available for the units enabled at that slot's Standort
            if (!empty($unitsPerStandort) && !empty($slotIds)) {
                foreach ($slots as $slot) {
                    $sid = (int) $slot->pid;
                    if (empty($unitsPerStandort[$sid])) {
                        continue;
                    }
                    $available = max(0, (int) $slot->getAvailableBehaelter());
                    foreach ($unitsPerStandort[$sid] as $uid => $_true) {
                        if ($available > ($unitMaxAvailable[$uid] ?? 0)) {
                            $unitMaxAvailable[$uid] = $available;
                        }
                    }
                }
            }

            // Append unit options at the bottom, without exceeding per-unit max availability and only for allowed units
            if (!empty($allowedUnitIds) && ($Units = WeinanlieferungUnitsModel::findAll()) !== null) {
                foreach ($Units as $unit) {
                    $unitId = (int) $unit->id;
                    if (empty($allowedUnitIds[$unitId])) {
                        continue; // this unit is not enabled on any shown standort
                    }

                    $unitContainers = (int) $unit->containers;
                    if ($unitContainers <= 0) {
                        continue;
                    }

                    $unitName = $unit->description ?: $unit->title; // visible unit name
                    $unitCap = (int) ($unitMaxAvailable[$unitId] ?? 0);
                    $multiplierMax = intdiv($unitCap, $unitContainers);
                    if ($multiplierMax <= 0) {
                        continue; // nothing available for this unit across shown slots
                    }

                    for ($m = 1; $m <= $multiplierMax; $m++) {
                        $value = (string) ($m * $unitContainers);
                        $label = $m . ' ' . $unitName;

                        $options[] = [
                            'value' => 'u' . $unitId . '-' . $value,
                            'label' => $label,
                        ];
                    }
                }
            }

            $arrData['filter']['kapazitaet']['options'] = $options;

            if (($Standorte = WeinanlieferungStandortModel::findBy(["id IN (" . implode(',', $standortIds) . ")", "id IN (SELECT tl_vr_wa_slot.pid FROM tl_vr_wa_slot WHERE tl_vr_wa_slot.id IN (" . implode(',', $slotIds) . "))"], null, ['order' => 'title ASC'])) !== null)
            {
                $arrData['filter']['standort']['options'] = array_combine($Standorte->fetchEach('id'), $Standorte->fetchEach('title'));
            }

//            $slots->reset();
            if (($slotsUnfiltered = WeinanlieferungSlotsModel::findMultiplePublishedByPids($standortIds)) !== null)
            {
                foreach ($slotsUnfiltered as $slot)
                {
                    $Tag = new Date($slot->time);
                    $arrData['filter']['tag']['options'][$Tag->dayBegin] = Date::parse(Date::getNumericDateFormat(), $Tag->dayBegin);
                }
            }

            /*if (isset($GLOBALS['TL_DCA']['tl_vr_wa_slot']['fields']['ernteart']['options']))
            {
                foreach ($GLOBALS['TL_DCA']['tl_vr_wa_slot']['fields']['ernteart']['options'] as $ernteart)
                {
                    $arrData['filter']['ernteart']['options'][$ernteart] = $GLOBALS['TL_LANG']['REF']['wa_ernteart'][$ernteart] ?? $ernteart;
                }
            }

            if (($Sorten = WeinanlieferungRebsorteModel::findAll(['order'=>'title ASC'])) !== null)
            {
                $arrData['filter']['sorte']['options'] = array_combine($Sorten->fetchEach('id'),$Sorten->fetchEach('title'));
            }

            if (($Leseart = WeinanlieferungLeseartModel::findAll(['order'=>'title ASC'])) !== null)
            {
                $arrData['filter']['leseart']['options'] = array_combine($Leseart->fetchEach('id'),$Leseart->fetchEach('title'));
            }*/


        }

        // Add page URL
        if ($objPage instanceof PageModel)
        {
            $arrData['pageUrl'] = $objPage->getFrontendUrl();
        }

        $template->setData($arrData);

        // Handle ajax
        if ($request->headers->get('VR-Ajax') == 'WaSlotsModule')
        {
            throw new ResponseException(new Response($this->insertTagParser->replace($template->parse())));
        }

        return $template->getResponse();
    }

}