<?php

namespace GriffinForms\Frontend\Html\Forms\Fields;

final class InputDate extends \GriffinForms\Frontend\Html\Forms\Fields\Format
{
    protected $js_date_format;
    protected $php_date_format;

    protected function setJsDateFormat()
    {
        $field_settings = $this->item->getProp('field_settings');
        $this->js_date_format = isset($field_settings['date_format']) ? esc_html($field_settings['date_format']) : 'mm-dd-yy';
    }

    protected function setPhpDateFormat()
    {
        $this->convertDateFormat();
    }

    protected function convertDateFormat()
    {
        $formats = array(
            'dd-mm-yy' => 'd-m-Y',
            'yy-mm-dd' => 'Y-m-d',
        );

        $this->php_date_format = isset($formats[$this->js_date_format]) ? $formats[$this->js_date_format] : 'm-d-Y';
    }

    protected function formControl()
    {
        $this->ensureDateFormats();
        $html = '<input type="text"';
        $html .= 'class="' . $this->html_ids['formcontrol'] . ' form-control mb-1"';
        $html .= $this->requiredAttr();
        $html .= $this->placeholderAttr();
        $html .= $this->valueAttr();
        $html .= $this->readOnlyAttr();
        $html .= $this->disabledAttr();
        $html .= ' data-gf-formpage="' . absint($this->data['formpage']) . '"';
        $html .= ' data-gf-logic-value-type="date"';
        $html .= ' data-gf-logic-date-format="' . esc_attr($this->js_date_format) . '">';
        return $html;
    }
    
    protected function valueAttr()
    {
        $this->ensureDateFormats();
        $value = $this->formatRenderedDateValue($this->value);
        return ' value="' . esc_attr($value) . '"';
    }

    protected function ensureDateFormats(): void
    {
        if (empty($this->js_date_format)) {
            $this->setJsDateFormat();
        }

        if (empty($this->php_date_format)) {
            $this->setPhpDateFormat();
        }
    }

    protected function formatRenderedDateValue($value): string
    {
        if ($value === '' || $value === null || $value === false) {
            return '';
        }

        if (is_numeric($value)) {
            $timestamp = (int) $value;
        } else {
            $timestamp = strtotime((string) $value);
        }

        if (!$timestamp) {
            return is_scalar($value) ? (string) $value : '';
        }

        return wp_date($this->php_date_format, $timestamp);
    }

    protected function setErrors()
    {
        $this->errors = array(
            'required',
            'minDate',
            'maxDate',
            'relativeMinDate',
            'relativeMaxDate',
            'dayType',
            'unique'
        );
    }
    
    protected function isMinDate()
    {
        if ($this->isCustomValidations() and array_key_exists('min', $this->validations)) {
            return true;
        } else {
            return false;
        }
    }
    
    protected function isMaxDate()
    {
        if ($this->isCustomValidations() and array_key_exists('max', $this->validations)) {
            return true;
        } else {
            return false;
        }
    }

    protected function isDayType()
    {
        if ($this->isCustomValidations() and array_key_exists('day_type', $this->validations) and $this->validations['day_type'] !== 'all_days') {
            return true;
        } else {
            return false;
        };
    }

    protected function isRelativeMinDate()
    {
        if ($this->isCustomValidations() and array_key_exists('relative_min', $this->validations)) {
            return true;
        } else {
            return false;
        }
    }

    protected function isRelativeMaxDate()
    {
        if ($this->isCustomValidations() and array_key_exists('relative_max', $this->validations)) {
            return true;
        } else {
            return false;
        }
    }

    protected function getDateLimit($type = 'min')
    {
        if ($this->isCustomValidations() and $this->validations['date_type'] === 'relative_date' and array_key_exists('relative_' . $type, $this->validations)) {
            return $this->getRelativeDate($type);
        }

        if ($this->isCustomValidations() and $this->validations['date_type'] === 'relative_date' and array_key_exists('relative_' . $type, $this->validations)) {
            return $this->getTimeStampDate($type);
        }

        return '';
    }

    protected function getRelativeDate($type = 'min')
    {
        $js_function = 'getRelative' . ucfirst($type) . 'Date()';
        return $js_function;
    }

    protected function getTimeStampDate($type = 'min')
    {
        return '"' . wp_date($this->php_date_format, $this->validations[$type]) . '"';
    }
    
    protected function minDateJs($error)
    {
        echo '
        $(actionBtn).hover(function() {
            $(formControl).each(checkMinDate);
        });

        $(formControl).keyup(checkMinDate);
        
        function checkMinDate() {
            
            let value = $(this).datepicker("getDate");

            if(value === null) {
                removeAlert($(this), "' . esc_js($error) . '");
                return;
            }
            
            value = Math.floor(value.getTime() / 1000);

            if (value < ' . esc_js($this->validations['min']) . ') {
                addAlert($(this), "' . esc_js($error) . '");
            } else {
                removeAlert($(this), "' . esc_js($error) . '");
            }
        }
    ';
    }
    
    protected function maxDateJs($error)
    {
        echo '
        $(actionBtn).hover(function() {
            $(formControl).each(checkMaxDate);
        });

        $(formControl).keyup(checkMaxDate);
        
        function checkMaxDate() {
            
            let value = $(this).datepicker("getDate");

            if(value === null) {
                removeAlert($(this), "' . esc_js($error) . '");
                return;
            }
            
            value = Math.floor(value.getTime() / 1000);

            if (value > ' . esc_js($this->validations['max']) . ') {
                addAlert($(this), "' . esc_js($error) . '");
            } else {
                removeAlert($(this), "' . esc_js($error) . '");
            }
        }
    ';
    }
    
    protected function dayTypeJs($error)
    {
        echo '
        $(actionBtn).hover(function() {
            $(formControl).each(checkDayType);
        });

        $(formControl).keyup(checkDayType);
        
        function checkDayType() {
            let value = $(this).datepicker("getDate");
            const allowedDay = "' . esc_js($this->validations['day_type']) . '";
            const dayNos = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "weekends", "weekdays"];
            let allowedDayNo = dayNos.indexOf(allowedDay);

            if(value === null) {
                removeAlert($(this), "' . esc_js($error) . '");
                return;
            }
            
            let selectedDayNo = value.getDay();

            if (allowedDayNo < 7) {
                if (selectedDayNo !== allowedDayNo) {
                    addAlert($(this), "' . esc_js($error) . '");
                } else {
                    removeAlert($(this), "' . esc_js($error) . '");
                }
            } else if (allowedDayNo === 7) {
                if (selectedDayNo !== 0 && selectedDayNo !== 6) {
                    addAlert($(this), "' . esc_js($error) . '");
                } else {
                    removeAlert($(this), "' . esc_js($error) . '");
                }
            } else if (allowedDayNo === 8) {
                if (selectedDayNo === 0 || selectedDayNo === 6) {
                    addAlert($(this), "' . esc_js($error) . '");
                } else {
                    removeAlert($(this), "' . esc_js($error) . '");
                }
            }
        }
    ';
    }

    protected function relativeMinDateJs($error)
    {
        $logic = ($this->validations['relative_min']['date_logic'] === 'before_date') ? '-' : '+';
    
        echo '
        $(actionBtn).hover(function() {
            $(formControl).each(checkRelativeMinDate);
        });
    
        $(formControl).keyup(checkRelativeMinDate);
        
        function checkRelativeMinDate() {
            let value = $(this).datepicker("getDate");
            let minDate = getRelativeMinDate();

            if (value === null) {
                removeAlert($(this), "' . esc_js($error) . '");
                return;
            }

            // Normalize both dates to midnight (00:00:00) to avoid time zone issues
            value.setHours(0, 0, 0, 0);  // Set the user-selected date to 00:00:00
            minDate.setHours(0, 0, 0, 0); // Set the minDate to 00:00:00

            // Compare the normalized values
            if (value.getTime() < minDate.getTime()) {
                addAlert($(this), "' . esc_js($error) . '");
            } else {
                removeAlert($(this), "' . esc_js($error) . '");
            }
        }
    
        function getRelativeMinDate() {
            let referenceDate = new Date(' . absint($this->relativeDateReference()) . ');
            
            // Ensure proper date calculation based on logic (before or after)
            referenceDate.setYear(referenceDate.getFullYear() ' . esc_js($logic) . ' ' . absint($this->validations['relative_min']['years']) . ');
            referenceDate.setMonth(referenceDate.getMonth() ' . esc_js($logic) . ' ' . absint($this->validations['relative_min']['months']) . ');
            referenceDate.setDate(referenceDate.getDate() ' . esc_js($logic) . ' (' . absint($this->validations['relative_min']['weeks']) . ' * 7));
            referenceDate.setDate(referenceDate.getDate() ' . esc_js($logic) . ' (' . absint($this->validations['relative_min']['days']) . ' + 0));
            return referenceDate;
        }
        ';
    }

    protected function relativeMaxDateJs($error)
    {
        $logic = ($this->validations['relative_max']['date_logic'] === 'before_date') ? '-' : '+';
    
        echo '
        $(actionBtn).hover(function() {
            $(formControl).each(checkRelativeMaxDate);
        });
    
        $(formControl).keyup(checkRelativeMaxDate);
        
        function checkRelativeMaxDate() {
            
            let value = $(this).datepicker("getDate");
            let maxDate = getRelativeMaxDate();
    
            if(value === null) {
                removeAlert($(this), "' . esc_js($error) . '");
                return;
            }
    
            // Normalize both dates to midnight (00:00:00) to avoid time zone issues
            value.setHours(0, 0, 0, 0);  // Set the user-selected date to 00:00:00
            maxDate.setHours(0, 0, 0, 0); // Set the maxDate to 00:00:00
    
            // Compare the normalized values
            if (value.getTime() > maxDate.getTime()) {
                addAlert($(this), "' . esc_js($error) . '");
            } else {
                removeAlert($(this), "' . esc_js($error) . '");
            }
        }
    
        function getRelativeMaxDate() {
            let referenceDate = new Date(' . esc_js($this->relativeDateReference('max')) . ');
            
            // Ensure proper date calculation based on logic (before or after)
            referenceDate.setYear(referenceDate.getFullYear() ' . esc_js($logic) . ' ' . absint($this->validations['relative_max']['years']) . ');
            referenceDate.setMonth(referenceDate.getMonth() ' . esc_js($logic) . ' ' . absint($this->validations['relative_max']['months']) . ');
            referenceDate.setDate(referenceDate.getDate() ' . esc_js($logic) . ' (' . absint($this->validations['relative_max']['weeks']) . ' * 7));
            referenceDate.setDate(referenceDate.getDate() ' . esc_js($logic) . ' (' . absint($this->validations['relative_max']['days']) . ' + 0));
            return referenceDate;
        }
        ';
    }

    protected function relativeDateReference($type = 'min')
    {
        $type = 'relative_' . $type;
        $date_variable = $this->validations[$type]['date_variable'];
        $method = 'get' . str_replace('_', '', $date_variable);
        $date = $this->$method();
        $date = strtotime($date) * 1000;
        return $date;
    }

    protected function getCurrentDate()
    {
        return wp_date(get_option('date_format'));
    }

    protected function getCurrentPagePublishDate()
    {
        return get_the_date();
    }

    protected function getCurrentPageEditDate()
    {
        return get_the_modified_date();
    }

    protected function getCurrentFormCreationDate()
    {
        $form = new \GriffinForms\Items\Form();
        $form->loadItem($this->data['form']);
        return $form->getProp('created');
    }
    
    protected function subItemJs()
    {
        echo '
        $(formControl).datepicker({
            dateFormat: "' . esc_js($this->js_date_format) . '",
            changeMonth: true,
            changeYear: true,
            yearRange: "-30:+5",
            onSelect: function() {
                $(this).trigger("input").trigger("change");
            },';
        
        // If using fixed dates, set minDate and maxDate
        if ($this->isMinDate() && !empty($this->validations['min'])) {
            $min_date = $this->validations['min'];
            echo 'minDate: new Date(' . esc_js($min_date) * 1000 . '),';  // Convert UNIX timestamp to JavaScript Date object
        } 
    
        if ($this->isMaxDate() && !empty($this->validations['max'])) {
            $max_date = $this->validations['max'];
            echo 'maxDate: new Date(' . esc_js($max_date) * 1000 . '),';  // Convert UNIX timestamp to JavaScript Date object
        }
    
        // If using relative dates, set relative minDate and maxDate
        if ($this->isRelativeMinDate() && !empty($this->validations['relative_min'])) {
            $relativeMinJs = 'getRelativeMinDate()'; // Function to get the relative minDate JS
            echo 'minDate: ' . esc_js($relativeMinJs) . ',';
        }
    
        if ($this->isRelativeMaxDate() && !empty($this->validations['relative_max'])) {
            $relativeMaxJs = 'getRelativeMaxDate()'; // Function to get the relative maxDate JS
            echo 'maxDate: ' . esc_js($relativeMaxJs) . ',';
        }
        
        echo '});';
    
        // Ensure proper date format is set in the JS
        $this->setDateFormatJs();
    }

    protected function setDateFormatJs()
    {
        echo '
        $(formControl).datepicker("option", "dateFormat", "' . esc_js($this->js_date_format) . '")' . PHP_EOL;
    }
}
