<?php

declare(strict_types=1);

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

namespace vonRotenberg\WeinanlieferungBundle\Model;

use Contao\Controller;
use Contao\Database;
use Contao\Date;
use Contao\FrontendUser;
use Contao\Model;
use Contao\Model\Registry;
use Contao\StringUtil;
use Doctrine\DBAL\Connection;

class WeinanlieferungSlotsModel extends Model
{
    /**
     * Table name
     * @var string
     */
    protected static $strTable = 'tl_vr_wa_slot';

    /**
     * Get allowed standort IDs for the current frontend user
     * @return array
     */
    protected static function getAllowedStandortIds(): array
    {
        // If no frontend user is logged in, return empty array
        if (!FrontendUser::getInstance()->id) {
            return [];
        }

        // Get member groups
        $memberGroups = StringUtil::deserialize(FrontendUser::getInstance()->groups, true);
        if (empty($memberGroups)) {
            return [];
        }

        // Get allowed standorts from member groups
        $db = Database::getInstance();
        $allowedStandorts = [];

        foreach ($memberGroups as $groupId) {
            $group = $db->prepare("SELECT standorts FROM tl_member_group WHERE id=?")
                        ->execute($groupId);

            if ($group->standorts) {
                $groupStandorts = StringUtil::deserialize($group->standorts, true);
                $allowedStandorts = array_merge($allowedStandorts, $groupStandorts);
            }
        }

        return array_unique($allowedStandorts);
    }

    public static function findPublishedById($intId, array $arrOptions=array())
    {
        $time = time();
        $t = static::$strTable;
        $arrColumns = array("$t.id=?");

        // Skip unsaved elements (see #2708)
        $arrColumns[] = "$t.tstamp!=0";
        $arrColumns[] = "$t.published='1'";

        $arrColumns[] = "($t.buchbar_ab<=$time OR $t.buchbar_ab = 0 OR $t.buchbar_ab IS NULL) AND $t.buchbar_bis>$time";

        // Check standort permissions
        $allowedStandortIds = static::getAllowedStandortIds();
        if (!empty($allowedStandortIds)) {
            $arrColumns[] = "$t.pid IN (" . implode(',', $allowedStandortIds) . ")";
        }

        if (!isset($arrOptions['order']))
        {
            $arrOptions['order'] = "$t.time ASC";
        }

        return static::findOneBy($arrColumns, $intId, $arrOptions);
    }

    public static function findPublishedByPid($intPid, array $arrOptions=array())
    {
        $time = time();
        $t = static::$strTable;
        $arrColumns = array("$t.pid=?");

        // Skip unsaved elements (see #2708)
        $arrColumns[] = "$t.tstamp!=0";
        $arrColumns[] = "$t.published='1'";

        $arrColumns[] = "($t.buchbar_ab<=$time OR $t.buchbar_ab = 0 OR $t.buchbar_ab IS NULL) AND $t.buchbar_bis>$time";

        // Check standort permissions
        $allowedStandortIds = static::getAllowedStandortIds();
        if (!empty($allowedStandortIds) && !in_array($intPid, $allowedStandortIds)) {
            return null; // Return null if the requested standort is not allowed
        }

        if (!isset($arrOptions['order']))
        {
            $arrOptions['order'] = "$t.time ASC";
        }

        return static::findBy($arrColumns, $intPid, $arrOptions);
    }

    public static function findMultiplePublishedByPids(array $arrPids, array $arrOptions=array())
    {
        if (empty($arrPids) || !\is_array($arrPids))
        {
            return null;
        }

        $arrPids = array_filter($arrPids, function($var) {
            return is_numeric($var);
        });

        if (empty($arrPids))
        {
            return null;
        }

        // Check standort permissions
        $allowedStandortIds = static::getAllowedStandortIds();
        if (!empty($allowedStandortIds)) {
            // Filter the provided PIDs by the allowed standort IDs
            $arrPids = array_intersect($arrPids, $allowedStandortIds);

            if (empty($arrPids)) {
                return null; // Return null if none of the requested standorts are allowed
            }
        }

        $time = time();
        $t = static::$strTable;
        $arrColumns = array("$t.pid IN (".implode(',',$arrPids).")");

        // Skip unsaved elements (see #2708)
        $arrColumns[] = "$t.tstamp!=0";
        $arrColumns[] = "$t.published='1'";

        $arrColumns[] = "($t.buchbar_ab<=$time OR $t.buchbar_ab = 0 OR $t.buchbar_ab IS NULL) AND $t.buchbar_bis>$time";

        if (!isset($arrOptions['order']))
        {
            $arrOptions['order'] = "$t.time ASC";
        }

        if (isset($arrOptions['column']))
        {
            $arrColumns = array_merge($arrColumns,$arrOptions['column']);
            $arrOptions = array_diff_key($arrOptions,['column'=>true]);
        }

        return static::findBy($arrColumns,null,$arrOptions);
    }

    public static function findAllFuturePublished(array $arrOptions=array())
    {
        $t = static::$strTable;
        $time = Date::floorToMinute();

        // Check standort permissions
        $allowedStandortIds = static::getAllowedStandortIds();
        $arrColumns = array("$t.time >= ?", "$t.tstamp!=0", "$t.published='1' AND ($t.buchbar_ab<=$time OR $t.buchbar_ab = 0 OR $t.buchbar_ab IS NULL) AND $t.buchbar_bis > ?");
        $arrValues = [$time, $time, $time];

        if (!empty($allowedStandortIds)) {
            $arrColumns[] = "$t.pid IN (" . implode(',', $allowedStandortIds) . ")";
        }

        if (!isset($arrOptions['order']))
        {
            $arrOptions['order'] = "$t.time ASC";
        }

        return static::findBy($arrColumns, $arrValues, $arrOptions);
    }

    public function getAvailableBehaelter(bool $inclOvercapacity = false, ?int $intOffset=null)
    {
        /** @var Connection $db */
        $db = Controller::getContainer()->get('database_connection');

        $ReservedBehaelter = $db->prepare("SELECT SUM(behaelter) FROM tl_vr_wa_reservation WHERE pid = ?")
            ->executeQuery([$this->id]);

        $intReserved = $ReservedBehaelter->fetchOne();
        $intOvercapacity = 0;

        if ($inclOvercapacity)
        {
            $intOvercapacity = $this->getOvercapacityBehaelter();
        }

        if ($intReserved === null)
        {
            $intReserved = 0;
        }

        if ($intOffset > 0)
        {
            $intReserved += $intOffset;
        }

        return (int) max(0,$this->behaelter + $intOvercapacity - $intReserved);
    }

    public function getOvercapacityBehaelter(bool $blnGross=false)
    {
        $intOvercapacity = round($this->behaelter/100*$this->overcapacity);

        if ($blnGross)
        {
            return $intOvercapacity;
        }

        /** @var Connection $db */
        $db = Controller::getContainer()->get('database_connection');

        $ReservedBehaelter = $db->prepare("SELECT SUM(behaelter) FROM tl_vr_wa_reservation WHERE pid = ?")
            ->executeQuery([$this->id]);

        $intReserved = $ReservedBehaelter->fetchOne();

        $intAmount = min($intOvercapacity,$this->behaelter+$intOvercapacity-$intReserved);

        return $intAmount;
    }
}