<?php

namespace CreoCode\ContaoFormSubmissions\Classes;

use Contao\BackendModule;
use Contao\Database;
use Contao\Input;
use Contao\System;
use Contao\Environment;

use CreoCode\ContaoFormSubmissions\Model\FormSubmissionsSetModel;


class Statistics extends BackendModule
{
    /**
     * Template
     * @var string
     */
    protected $strTemplate = 'form_submissions_statistics';

    /**
     * Generate the module
     */
    protected function compile(): void
    {
        System::loadLanguageFile('tl_form_submissions');
        $lang = $GLOBALS['TL_LANG']['tl_form_submissions'];

        $arrForms = FormSubmissionsSetModel::findAll();

        if (!$arrForms) {
            $this->Template->statisticNotAvailable = true;
            return;
        }

        // Aktuelle Parameter (mit sinnvollen Defaults)
        $preset  = Input::get('preset')   ?: 'last_7_days';
        $formSet = Input::get('form_set') ?: 'showAll';
        $view    = Input::get('view')     ?: 'day';

        // Whitelist-Validierung
        $validViews = ['day', 'month'];
        if (!in_array($view, $validViews, true)) {
            $view = 'day';
        }

        // Zeitraum-Presets aus Sprachdatei
        $presets = [
            'today'        => $lang['stat_preset_today']        ?? 'Today',
            'yesterday'    => $lang['stat_preset_yesterday']    ?? 'Yesterday',
            'last_7_days'  => $lang['stat_preset_last_7_days']  ?? 'Last 7 days',
            'last_30_days' => $lang['stat_preset_last_30_days'] ?? 'Last 30 days',
            'this_month'   => $lang['stat_preset_this_month']   ?? 'This month',
            'last_month'   => $lang['stat_preset_last_month']   ?? 'Last month',
            'this_year'    => $lang['stat_preset_this_year']    ?? 'This year',
            'last_year'    => $lang['stat_preset_last_year']    ?? 'Last year',
            'custom'       => $lang['stat_preset_custom']       ?? 'Custom',
        ];

        // Preset-Optionen aufbauen
        $strPresetOptions = '';
        foreach ($presets as $value => $label) {
            $strPresetOptions .= sprintf(
                '<option value="%s"%s>%s</option>',
                $value,
                $preset === $value ? ' selected' : '',
                htmlspecialchars($label)
            );
        }

        // Preset nach Aufbau des $presets-Arrays validieren
        if (!array_key_exists($preset, $presets)) {
            $preset = 'last_7_days';
        }

        // Formular-Optionen aufbauen
        $strFormOptions = sprintf(
            '<option value="showAll"%s>%s</option>',
            $formSet === 'showAll' ? ' selected' : '',
            htmlspecialchars($lang['stat_all_forms'] ?? '')
        );
        foreach ($arrForms as $form) {
            $strFormOptions .= sprintf(
                '<option value="%s"%s>%s</option>',
                $form->id,
                (string) $formSet === (string) $form->id ? ' selected' : '',
                htmlspecialchars($form->form_title)
            );
        }

        // Ansicht-Optionen aufbauen
        $strViewOptions  = sprintf('<option value="day"%s>%s</option>',   $view === 'day'   ? ' selected' : '', htmlspecialchars($lang['stat_view_day']   ?? ''));
        $strViewOptions .= sprintf('<option value="month"%s>%s</option>', $view === 'month' ? ' selected' : '', htmlspecialchars($lang['stat_view_month'] ?? ''));

        // Start- und Enddatum aus Preset berechnen
        [$startDt, $endDt] = $this->calculateDateRange($preset);

        $startTs = $startDt->getTimestamp();
        $endTs   = $endDt->getTimestamp();

        // Daten abfragen
        $db = Database::getInstance();

        if ($formSet !== 'showAll') {
            $objFormData = $db->prepare(
                'SELECT id, tstamp FROM tl_form_submissions WHERE tstamp BETWEEN ? AND ? AND pid=?'
            )->execute($startTs, $endTs, (int) $formSet)->fetchAllAssoc();
        } else {
            $objFormData = $db->prepare(
                'SELECT id, tstamp FROM tl_form_submissions WHERE tstamp BETWEEN ? AND ?'
            )->execute($startTs, $endTs)->fetchAllAssoc();
        }

        // Zeitraum-Beschriftung für die Chart-Überschrift
        $periodLabel = $presets[$preset] ?? ($lang['stat_preset_custom'] ?? 'Custom');
        if ($preset !== 'custom') {
            $periodLabel .= ': ' . $startDt->format('d.m.Y') . ' – ' . $endDt->format('d.m.Y');
        } else {
            $periodLabel = $startDt->format('d.m.Y') . ' – ' . $endDt->format('d.m.Y');
        }

        // Template-Variablen setzen
        $this->Template->action        = Environment::get('request');
        $this->Template->presetOptions = $strPresetOptions;
        $this->Template->formOptions   = $strFormOptions;
        $this->Template->viewOptions   = $strViewOptions;
        $this->Template->preset        = $preset;
        $this->Template->view          = $view;
        $this->Template->startDate     = $startDt->format('Y-m-d');
        $this->Template->endDate       = $endDt->format('Y-m-d');
        $this->Template->displayStart  = $startDt->format('d-m-Y');
        $this->Template->displayEnd    = $endDt->format('d-m-Y');
        $this->Template->periodLabel   = $periodLabel;
        $this->Template->searchMode    = true;
        $this->Template->objFormData   = $objFormData ?: [];

        // chart.js einbinden
        $GLOBALS['TL_JAVASCRIPT'][] = 'bundles/contaoformsubmissions/vendor/chartjs/Chart.bundle'
            . (System::getContainer()->get('kernel')->isDebug() ? '' : '.min')
            . '.js';
    }

    /**
     * Berechnet Start- und Enddatum anhand des gewählten Presets.
     * Bei 'custom' werden die GET-Parameter start/end verwendet.
     *
     * @return array{0: \DateTime, 1: \DateTime}
     */
    private function calculateDateRange(string $preset): array
    {
        $now = new \DateTime();

        switch ($preset) {
            case 'today':
                $start = (clone $now)->setTime(0, 0, 0);
                $end   = (clone $now)->setTime(23, 59, 59);
                break;

            case 'yesterday':
                $start = (clone $now)->modify('-1 day')->setTime(0, 0, 0);
                $end   = (clone $now)->modify('-1 day')->setTime(23, 59, 59);
                break;

            case 'last_30_days':
                $start = (clone $now)->modify('-29 days')->setTime(0, 0, 0);
                $end   = (clone $now)->setTime(23, 59, 59);
                break;

            case 'this_month':
                $start = (clone $now)->modify('first day of this month')->setTime(0, 0, 0);
                $end   = (clone $now)->setTime(23, 59, 59);
                break;

            case 'last_month':
                $start = (clone $now)->modify('first day of last month')->setTime(0, 0, 0);
                $end   = (clone $now)->modify('last day of last month')->setTime(23, 59, 59);
                break;

            case 'this_year':
                $start = (clone $now)->modify('first day of January this year')->setTime(0, 0, 0);
                $end   = (clone $now)->setTime(23, 59, 59); // bis heute, nicht bis Jahresende
                break;

            case 'last_year':
                $start = (clone $now)->modify('first day of January last year')->setTime(0, 0, 0);
                $end   = (clone $now)->modify('last day of December last year')->setTime(23, 59, 59);
                break;

            case 'custom':
                $startStr = Input::get('start') ?: '';
                $endStr   = Input::get('end')   ?: '';
                $start    = $startStr ? \DateTime::createFromFormat('d-m-Y', $startStr) : null;
                $end      = $endStr   ? \DateTime::createFromFormat('d-m-Y', $endStr)   : null;
                $start    = ($start instanceof \DateTime) ? $start->setTime(0, 0, 0)   : (clone $now)->modify('-6 days')->setTime(0, 0, 0);
                $end      = ($end   instanceof \DateTime) ? $end->setTime(23, 59, 59)  : (clone $now)->setTime(23, 59, 59);
                break;

            case 'last_7_days':
            default:
                $start = (clone $now)->modify('-6 days')->setTime(0, 0, 0);
                $end   = (clone $now)->setTime(23, 59, 59);
                break;
        }

        return [$start, $end];
    }
}
