<?php

namespace WeDevs\Wpuf\Pro\Fields;

/**
 * Date of Birth Field Class
 *
 * Predefined date of birth field with fixed meta key for user profiles/registration
 *
 * @since 4.2.5
 */
class Field_Date_Of_Birth extends Profile_Field {

    /**
     * Default year range for datepicker
     * Format: '-100:+100' means 100 years in the past, 100 years in the future
     *
     * @var string
     */
    const DEFAULT_YEAR_RANGE = '-100:+100';

    /**
     * Days per week for week-to-day conversion
     *
     * @var int
     */
    const DAYS_PER_WEEK = 7;

    /**
     * Constructor
     *
     * @since 4.2.5
     */
    public function __construct() {
        $this->name       = __( 'Date of Birth', 'wpuf-pro' );
        $this->input_type = 'date_of_birth_field';
        $this->icon       = 'dob';

        $this->enqueue_scripts();
    }

    /**
     * Enqueue scripts
     *
     * @since 4.2.5
     */
    public function enqueue_scripts() {
        wp_enqueue_script( 'jquery-ui-timepicker', WPUF_PRO_ASSET_URI . '/js/jquery-ui-timepicker-addon.js', [ 'jquery-ui-datepicker' ], '1.2' );
    }

    /**
     * Render the Date of Birth field
     *
     * @since 4.2.5
     *
     * @since 4.2.13 Added support for showing age and death date
     * 
     * @param array  $field_settings
     * @param int    $form_id
     * @param string $type
     * @param int    $post_id
     *
     * @return void
     */
    public function render( $field_settings, $form_id, $type = 'post', $post_id = null ) {
        // Get stored value
        if ( isset( $post_id ) && 0 !== (int) $post_id ) {
            $value = $this->get_meta( $post_id, $field_settings['name'], $type );
        } else {
            $value = isset( $field_settings['default'] ) ? $field_settings['default'] : '';
        }

        // Convert stored YYYY-MM-DD format to display format if needed
        if ( ! empty( $value ) ) {
            $date_obj = \DateTime::createFromFormat( 'Y-m-d', $value );
            if ( $date_obj ) {
                $format = isset( $field_settings['format'] ) ? $field_settings['format'] : 'dd/mm/yy';
                $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );
                $value = $date_obj->format( $php_format );
            }
        }

        $name             = $field_settings['name'];
        $is_required      = isset( $field_settings['required'] ) ? $field_settings['required'] : 'no';
        $is_readonly      = isset( $field_settings['readonly'] ) ? $field_settings['readonly'] : 'no';
        $show_age         = isset( $field_settings['show_age'] ) ? $field_settings['show_age'] : 'no';
        $show_age_months  = isset( $field_settings['show_age_months'] ) ? $field_settings['show_age_months'] : 'no';
        $show_death_date  = isset( $field_settings['show_death_date'] ) ? $field_settings['show_death_date'] : 'no';
        $format           = isset( $field_settings['format'] ) ? $field_settings['format'] : 'dd/mm/yy';
        // Get stored death date value if editing
        $death_date_value = '';
        if ( isset( $post_id ) && 0 !== (int) $post_id ) {
            $death_date_raw = $this->get_meta( $post_id, 'wpuf_death_date', $type );
            if ( ! empty( $death_date_raw ) ) {
                $death_date_obj = \DateTime::createFromFormat( 'Y-m-d', $death_date_raw );
                if ( $death_date_obj ) {
                    $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );
                    $death_date_value = $death_date_obj->format( $php_format );
                }
            }
        }

        $this->field_print_label( $field_settings, $form_id ); ?>

        <div class="wpuf-fields">
            <input
                id="wpuf-dob-<?php echo $name; ?>"
                type="text"
                autocomplete="off"
                class="datepicker wpuf-date-field wpuf-dob-field <?php echo 'wpuf_' . $name . '_' . $form_id; ?>"
                data-required="<?php echo $is_required; ?>"
                data-type="text"
                name="<?php echo esc_attr( $name ); ?>"
                placeholder="<?php echo esc_attr( $format ); ?>"
                value="<?php echo esc_attr( $value ); ?>"
                size="30"
                data-format="<?php echo esc_attr( $format ); ?>"
                data-time="no"
                data-mintime="<?php echo ! empty( $field_settings['mintime'] ) ? esc_attr( $field_settings['mintime'] ) : ''; ?>"
                data-maxtime="<?php echo ! empty( $field_settings['maxtime'] ) ? esc_attr( $field_settings['maxtime'] ) : ''; ?>"
            />

            <?php if ( 'yes' === $show_age ) : ?>
                <div class="wpuf-dob-age wpuf-dob-age-<?php echo $name; ?>" style="margin-top: 8px; font-size: 14px; color: #666;"></div>
            <?php endif; ?>

            <?php if ( 'yes' === $show_death_date ) : ?>
                <div class="wpuf-label">
                    <label for="wpuf-death-date-<?php echo $name; ?>">
                        <?php esc_html_e( 'Death Date', 'wpuf-pro' ); ?>
                    </label>
                </div>
                <div class="wpuf-fields">
                    <input
                        id="wpuf-death-date-<?php echo $name; ?>"
                        type="text"
                        autocomplete="off"
                        class="datepicker wpuf-date-field wpuf-death-date-field <?php echo 'wpuf_death_date_' . $form_id; ?>"
                        data-type="text"
                        name="wpuf_death_date"
                        placeholder="<?php echo esc_attr( $format ); ?>"
                        value="<?php echo esc_attr( $death_date_value ); ?>"
                        size="30"
                        data-format="<?php echo esc_attr( $format ); ?>"
                        data-time="no"
                    />
                </div>
            <?php endif; ?>

            <?php $this->help_text( $field_settings ); ?>
        </div>

        <script type="text/javascript">
            jQuery(document).ready(function($) {
                // Use setTimeout to ensure this runs after global field initialization
                setTimeout(function() {
                    var $dateField = $("#wpuf-dob-<?php echo $name; ?>");
                    var $deathDateField = $("#wpuf-death-date-<?php echo $name; ?>");
                    var $ageDisplay = $('.wpuf-dob-age-<?php echo $name; ?>');
                    var showAge = <?php echo 'yes' === $show_age ? 'true' : 'false'; ?>;
                    var showAgeMonths = <?php echo 'yes' === $show_age_months ? 'true' : 'false'; ?>;
                    var showDeathDate = <?php echo 'yes' === $show_death_date ? 'true' : 'false'; ?>;
                    var isReadonly = <?php echo 'yes' === $is_readonly ? 'true' : 'false'; ?>;

                    if ( $dateField.length === 0 ) {
                        return;
                    }

                    // Function to parse date string to Date object
                    function parseDateFromString(dateStr) {
                        if (!dateStr) return null;

                        var format = '<?php echo esc_js( $format ); ?>';
                        var parts = dateStr.split(/[\/\-]/);

                        if ( parts.length !== 3 ) return null;

                        var day, month, year;

                        if ( 'dd/mm/yy' === format || 'dd-mm-yy' === format ) {
                            day = parseInt(parts[0], 10);
                            month = parseInt(parts[1], 10) - 1;
                            year = parseInt(parts[2], 10);
                        } else if ( 'mm/dd/yy' === format || 'mm-dd-yy' === format ) {
                            day = parseInt(parts[1], 10);
                            month = parseInt(parts[0], 10) - 1;
                            year = parseInt(parts[2], 10);
                        } else if ( 'yy/mm/dd' === format || 'yy-mm-dd' === format ) {
                            day = parseInt(parts[2], 10);
                            month = parseInt(parts[1], 10) - 1;
                            year = parseInt(parts[0], 10);
                        } else {
                            return null;
                        }

                        return new Date(year, month, day);
                    }

                    // Function to calculate age text
                    function calculateAgeText(birthDate, endDate) {
                        if ( !birthDate ) {
                            return null;
                        }

                        // Use provided end date or default to today
                        var referenceDate = endDate ? endDate : new Date();
                        var years = referenceDate.getFullYear() - birthDate.getFullYear();
                        var months = referenceDate.getMonth() - birthDate.getMonth();

                        if (months < 0) {
                            years--;
                            months += 12;
                        } else if (months === 0) {
                            if (referenceDate.getDate() < birthDate.getDate()) {
                                years--;
                                months = 11;
                            }
                        } else if (referenceDate.getDate() < birthDate.getDate()) {
                            months--;
                        }

                        if ( years < 0 ) {
                            return null;
                        }

                        var ageText = '<?php esc_html_e( 'Age: ', 'wpuf-pro' ); ?>' + years + ' <?php esc_html_e( 'years', 'wpuf-pro' ); ?>';

                        if ( showAgeMonths ) {
                            if ( months > 0 ) {
                                ageText += ', ' + months + ' <?php esc_html_e( 'months', 'wpuf-pro' ); ?>';
                            }
                        }

                        return ageText;
                    }

                    // Handle readonly field
                    if ( isReadonly ) {
                        $dateField.prop('readonly', true);

                        <?php if ( 'yes' === $show_age ) : ?>
                        // Update age display for readonly fields
                        var initialValue = $dateField.val();
                        if ( initialValue ) {
                            var date = parseDateFromString(initialValue);
                            if ( date ) {
                                var ageText = calculateAgeText(date);
                                if ( ageText ) {
                                    if ( $ageDisplay.length ) {
                                        $ageDisplay.text( ageText );
                                    }
                                }
                            }
                        }
                        <?php endif; ?>
                        return;
                    }

                    var date_default = {
                        dateFormat: '<?php echo esc_js( $format ); ?>',
                        changeMonth: true,
                        changeYear: true,
                        yearRange: '<?php echo esc_js( self::DEFAULT_YEAR_RANGE ); ?>',
                        maxDate: 0
                    };

                    function parseDateValue(dateStr) {
                        if ( !dateStr ) {
                            return null;
                        }

                        dateStr = dateStr.trim();

                        if ( !dateStr ) {
                            return null;
                        }

                        // Parse absolute date only (dd-mm-yyyy or dd/mm/yyyy)
                        var dateParts = dateStr.split(/[-/]/);

                        if ( dateParts.length === 3 ) {
                            var year = parseInt(dateParts[2], 10);
                            var month = parseInt(dateParts[1], 10) - 1;
                            var day = parseInt(dateParts[0], 10);
                            return new Date(year, month, day);
                        }

                        return null;
                    }

                    <?php
                    $maxtime = '';
                    $mintime = '';

                    $has_mintime = isset( $field_settings['mintime'] ) && strlen( trim( $field_settings['mintime'] ) ) > 0;
                    $has_maxtime = isset( $field_settings['maxtime'] ) && strlen( trim( $field_settings['maxtime'] ) ) > 0;

                    if ( $has_mintime || $has_maxtime ) {
                        if ( $has_mintime ) {
                            $mintime = str_replace( '/', '-', trim( $field_settings['mintime'] ) );
                        }
                        if ( $has_maxtime ) {
                            $maxtime = str_replace( '/', '-', trim( $field_settings['maxtime'] ) );
                        }
                    ?>
                    var dateObj = jQuery.extend({}, date_default);

                    <?php if ( $has_mintime ) { ?>
                    var parsedMinDate = parseDateValue("<?php echo esc_js( $mintime ); ?>");

                    if ( parsedMinDate !== null ) {
                        dateObj.minDate = parsedMinDate;
                    }
                    <?php } ?>

                    <?php if ( $has_maxtime ) { ?>
                    var parsedMaxDate = parseDateValue("<?php echo esc_js( $maxtime ); ?>");

                    if ( parsedMaxDate !== null ) {
                        dateObj.maxDate = parsedMaxDate;
                    }
                    <?php } ?>

                    if ( $dateField.hasClass('hasDatepicker') ) {
                        $dateField.datepicker('destroy');
                    }

                    $dateField.datepicker(dateObj);
                    <?php } else { ?>
                    if ( $dateField.hasClass('hasDatepicker') ) {
                        $dateField.datepicker('destroy');
                    }

                    $dateField.datepicker(date_default);
                    <?php } ?>

                        $dateField.addClass('wpuf-initialized');

                    // Initialize death date datepicker if enabled
                    if ( showDeathDate && $deathDateField.length > 0 ) {
                        var deathDateConfig = {
                            dateFormat: '<?php echo esc_js( $format ); ?>',
                            changeMonth: true,
                            changeYear: true,
                            yearRange: '<?php echo esc_js( self::DEFAULT_YEAR_RANGE ); ?>'
                            // No maxDate restriction for death date
                        };

                        if ( $deathDateField.hasClass('hasDatepicker') ) {
                            $deathDateField.datepicker('destroy');
                        }

                        $deathDateField.datepicker(deathDateConfig);
                        $deathDateField.addClass('wpuf-initialized');
                    }

                    // Age update function
                    function updateAge() {
                        if ( !showAge ) {
                            return;
                        }

                        var dateValue = $dateField.val();
                        if ( dateValue ) {
                            var birthDate = parseDateFromString(dateValue);
                            if ( birthDate ) {
                                // Check if death date exists and use it as reference
                                var endDate = null;
                                if ( showDeathDate && $deathDateField.length > 0 ) {
                                    var deathDateValue = $deathDateField.val();
                                    if ( deathDateValue ) {
                                        endDate = parseDateFromString(deathDateValue);
                                    }
                                }

                                var ageText = calculateAgeText(birthDate, endDate);
                                if ( ageText ) {
                                    if ( $ageDisplay.length > 0 ) {
                                        $ageDisplay.text( ageText ).show();
                                    }
                                }
                            }
                        } else {
                            if ( $ageDisplay.length > 0 ) {
                                $ageDisplay.text( '' );
                            }
                        }
                    }

                    if ( showAge ) {
                        $dateField.on('change', updateAge);

                        // Also update age when death date changes
                        if ( showDeathDate && $deathDateField.length > 0 ) {
                            $deathDateField.on('change', updateAge);
                        }

                        updateAge();
                    }
                }, 100); // End setTimeout
            });
        </script>

        <?php $this->after_field_print_label();
    }

    /**
     * Get field options setting
     *
     * @since 4.2.5
     * 
     * @since 4.2.13 Added new options for date format, age display, and death date support
     *
     * @return array
     */
    public function get_options_settings() {
        // Get default options but exclude the name field since we'll provide our own meta_key field
        $filtered_options = $this->get_default_option_settings( true, [ 'name' ] );

        $dob_options = [
            [
                'name'      => 'name',
                'title'     => __( 'Meta Key', 'wpuf-pro' ),
                'type'      => 'text',
                'section'   => 'basic',
                'priority'  => 11,
                'readonly'  => true,
                'help_text' => __( 'The meta key used to store this field data in the database. This is fixed to "wpuf_dob" and cannot be changed.', 'wpuf-pro' ),
            ],

            [
                'name'      => 'format',
                'title'     => __( 'Date Format', 'wpuf-pro' ),
                'type'      => 'select',
                'section'   => 'advanced',
                'priority'  => 23,
                'options'   => [
                    'dd/mm/yy' => __( 'dd/mm/yyyy (e.g., 25/12/2024)', 'wpuf-pro' ),
                    'mm/dd/yy' => __( 'mm/dd/yyyy (e.g., 12/25/2024)', 'wpuf-pro' ),
                    'yy/mm/dd' => __( 'yyyy/mm/dd (e.g., 2024/12/25)', 'wpuf-pro' ),
                    'dd-mm-yy' => __( 'dd-mm-yyyy (e.g., 25-12-2024)', 'wpuf-pro' ),
                    'mm-dd-yy' => __( 'mm-dd-yyyy (e.g., 12-25-2024)', 'wpuf-pro' ),
                    'yy-mm-dd' => __( 'yyyy-mm-dd (e.g., 2024-12-25)', 'wpuf-pro' ),
                ],
                'default'   => 'dd/mm/yy',
                'help_text' => __( 'Select the date format for display', 'wpuf-pro' ),
            ],

            [
                'name'          => 'show_age',
                'title'         => '',
                'type'          => 'checkbox',
                'is_single_opt' => true,
                'options'       => [
                    'yes' => __( 'Show age as number', 'wpuf-pro' ),
                ],
                'section'       => 'basic',
                'priority'      => 13,
                'help_text'     => __( 'Display calculated age alongside the date of birth', 'wpuf-pro' ),
            ],

            [
                'name'          => 'show_age_months',
                'title'         => '',
                'type'          => 'checkbox',
                'is_single_opt' => true,
                'options'       => [
                    'yes' => __( 'Show months in age calculation', 'wpuf-pro' ),
                ],
                'section'       => 'basic',
                'priority'      => 13.5,
                'help_text'     => __( 'Display age with months (e.g., "25 years, 3 months")', 'wpuf-pro' ),
            ],

            [
                'name'          => 'show_death_date',
                'title'         => '',
                'type'          => 'checkbox',
                'is_single_opt' => true,
                'options'       => [
                    'yes' => __( 'Show Death Date', 'wpuf-pro' ),
                ],
                'section'       => 'basic',
                'priority'      => 14,
                'help_text'     => __( 'When enabled, a Death Date field appears below DoB. Age will be calculated as Death Date minus Birth Date.', 'wpuf-pro' ),
            ],

            [
                'name'      => 'mintime',
                'title'     => __( 'Minimum Date', 'wpuf-pro' ),
                'type'      => 'text',
                'section'   => 'advanced',
                'priority'  => 26,
                'help_text' => __( 'Enter earliest selectable date (e.g., 01-01-1900)', 'wpuf-pro' ),
            ],

            [
                'name'      => 'maxtime',
                'title'     => __( 'Maximum Date', 'wpuf-pro' ),
                'type'      => 'text',
                'section'   => 'advanced',
                'priority'  => 27,
                'help_text' => __( 'Enter latest selectable date (e.g., 31-12-2024)', 'wpuf-pro' ),
            ],
        ];

        return array_merge( $filtered_options, $dob_options );
    }

    /**
     * Get the field props
     *
     * @since 4.2.5
     * 
     * @since 4.2.13 Added new properties for age display and death date support
     *
     * @return array
     */
    public function get_field_props() {
        $defaults = $this->default_attributes();
        $props    = [
            'input_type'       => 'date_of_birth',
            'label'            => __( 'Date of Birth', 'wpuf-pro' ),
            'name'             => 'wpuf_dob', // Fixed meta key for form builder
            'is_meta'          => 'yes',
            'format'           => 'dd/mm/yy',
            'show_age'         => 'no',
            'show_age_months'  => 'no',
            'show_death_date'  => 'no',
            'readonly'         => 'no',
            'id'               => 0,
            'is_new'           => true,
            'show_in_post'     => 'yes',
            'hide_field_label' => 'no',
        ];

        return array_merge( $defaults, $props );
    }

    /**
     * Prepare entry
     *
     * @since 4.2.5
     *
     * @param $field
     *
     * @return mixed
     */
    public function prepare_entry( $field ) {
        check_ajax_referer( 'wpuf_form_add' );

        $val = isset( $_POST[ $field['name'] ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field['name'] ] ) ) : '';

        if ( empty( $val ) ) {
            return '';
        }

        // Convert datepicker format to YYYY-MM-DD for storage
        $format = isset( $field['format'] ) ? $field['format'] : 'dd/mm/yy';
        $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );

        $date = \DateTime::createFromFormat( $php_format, $val );
        if ( $date ) {
            return $date->format( 'Y-m-d' );
        }

        return '';
    }

    /**
     * Render field data for display
     *
     * @since 4.2.5
     *
     * @param mixed $data
     * @param array $field
     *
     * @return string
     */
    public function render_field_data( $data, $field ) {
        $data       = is_array( $data ) ? array_pop( $data ) : $data;
        $hide_label = isset( $field['hide_field_label'] )
            ? wpuf_validate_boolean( $field['hide_field_label'] )
            : false;

        $container_classnames = [ 'wpuf-field-data', 'wpuf-field-data-' . $this->input_type ];

        if ( empty( $data ) ) {
            return '';
        }

        // Format the date for display (data is stored in YYYY-MM-DD format)
        $format          = isset( $field['format'] ) ? $field['format'] : 'dd/mm/yy';
        $show_age        = isset( $field['show_age'] ) ? $field['show_age'] : 'no';
        $show_age_months = isset( $field['show_age_months'] ) ? $field['show_age_months'] : 'no';

        $formatted_date = self::format_date_for_display( $data, $format );
        $age_text       = '';

        if ( 'yes' === $show_age ) {
            $age_data = self::calculate_age( $data, 'yes' === $show_age_months );
            if ( $age_data !== false ) {
                if ( is_array( $age_data ) ) {
                    // Array with years and months
                    if ( $age_data['months'] > 0 ) {
                        $age_text = sprintf(
                            /* translators: 1: years, 2: months */
                            __( ' (Age: %1$d years, %2$d months)', 'wpuf-pro' ),
                            $age_data['years'],
                            $age_data['months']
                        );
                    } else {
                        $age_text = sprintf(
                            /* translators: %d: age in years */
                            __( ' (Age: %d years)', 'wpuf-pro' ),
                            $age_data['years']
                        );
                    }
                } else {
                    // Just years
                    $age_text = sprintf(
                        /* translators: %d: age in years */
                        __( ' (Age: %d years)', 'wpuf-pro' ),
                        $age_data
                    );
                }
            }
        }

        ob_start();
        ?>
            <li class="<?php echo esc_attr( implode( ' ', $container_classnames ) ); ?>">
                <?php if ( ! $hide_label ) : ?>
                    <label><?php echo esc_html( $field['label'] ); ?>:</label>
                <?php endif; ?>
                <?php echo esc_html( $formatted_date . $age_text ); ?>
            </li>
        <?php
        return ob_get_clean();
    }

    /**
     * Validate date of birth during form submission
     *
     * Ensures the date is valid and in the past (not future)
     *
     * @since 4.2.5
     * 
     * @since 4.2.13 Added validation for death date and cross-validation with birth date
     *
     * @param string $error Existing error message from previous validation hooks
     *
     * @return string Error message if validation fails, or empty string if valid
     */
    public static function validate_date_of_birth( $error ) {
        // If there's already an error from a previous hook, preserve it
        if ( ! empty( $error ) ) {
            return $error;
        }

        $form_id = isset( $_POST['form_id'] ) ? intval( wp_unslash( $_POST['form_id'] ) ) : 0;
        if ( ! $form_id ) {
            return $error;
        }

        $form        = new \WeDevs\Wpuf\Admin\Forms\Form( $form_id );
        $form_fields = $form->get_fields();

        foreach ( $form_fields as $field ) {
            if ( 'date_of_birth_field' !== $field['template'] && 'date_of_birth_field' !== $field['input_type'] ) {
                continue;
            }

            $field_name = isset( $field['name'] ) ? $field['name'] : '';

            // Validate field name to prevent arbitrary POST data access
            if ( empty( $field_name ) || ! preg_match( '/^[a-zA-Z0-9_-]+$/', $field_name ) ) {
                continue;
            }

            $submitted_value = isset( $_POST[ $field_name ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field_name ] ) ) : '';

            // Skip if field is not required and empty
            $is_required = isset( $field['required'] ) && 'yes' === $field['required'];
            if ( empty( $submitted_value ) && ! $is_required ) {
                continue;
            }

            if ( empty( $submitted_value ) && $is_required ) {
                $field_label = isset( $field['label'] ) ? $field['label'] : __( 'Date of Birth', 'wpuf-pro' );
                return sprintf(
                    /* translators: %s: Field label */
                    __( '%s is required', 'wpuf-pro' ),
                    $field_label
                );
            }

            $validation_error = self::validate_date_value( $submitted_value, $field );

            if ( ! empty( $validation_error ) ) {
                return $validation_error;
            }

            // Validate death date if show_death_date is enabled
            $show_death_date = isset( $field['show_death_date'] ) && 'yes' === $field['show_death_date'];

            if ( $show_death_date && isset( $_POST['wpuf_death_date'] ) ) {
                $death_date_value = sanitize_text_field( wp_unslash( $_POST['wpuf_death_date'] ) );

                // Only validate if death date is provided
                if ( ! empty( $death_date_value ) ) {
                    $field_label = isset( $field['label'] ) ? $field['label'] : __( 'Date of Birth', 'wpuf-pro' );

                    // Validate death date format
                    $death_validation_error = self::validate_date_value( $death_date_value, $field );

                    if ( ! empty( $death_validation_error ) ) {
                        // Replace field label with "Death Date" for clarity
                        $death_validation_error = str_replace(
                            $field_label,
                            __( 'Death Date', 'wpuf-pro' ),
                            $death_validation_error
                        );
                        return $death_validation_error;
                    }

                    // Cross-validate: Death date must be >= Birth date
                    $format = isset( $field['format'] ) ? $field['format'] : 'dd/mm/yy';
                    $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );

                    $dob_date = \DateTime::createFromFormat( $php_format, $submitted_value );
                    $death_date = \DateTime::createFromFormat( $php_format, $death_date_value );

                    if ( $dob_date && $death_date ) {
                        $dob_date->setTime( 0, 0, 0 );
                        $death_date->setTime( 0, 0, 0 );

                        if ( $death_date < $dob_date ) {
                            return __( 'Death Date cannot be earlier than Date of Birth', 'wpuf-pro' );
                        }
                    }
                }
            }
        }

        return $error;
    }

    /**
     * Validate a single date of birth value
     *
     * @since 4.2.5
     *
     * @param string $date_value Submitted date value in datepicker format
     * @param array  $field_settings Field configuration
     *
     * @return string Error message if validation fails, or empty string if valid
     */
    private static function validate_date_value( $date_value, $field_settings ) {
        $format = isset( $field_settings['format'] ) ? $field_settings['format'] : 'dd/mm/yy';
        $field_label = isset( $field_settings['label'] ) ? $field_settings['label'] : __( 'Date of Birth', 'wpuf-pro' );

        // Convert jQuery date format to PHP format
        $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );

        // Parse submitted date
        $date = \DateTime::createFromFormat( $php_format, $date_value );

        if ( false === $date ) {
            return sprintf(
                /* translators: 1: Field label, 2: Expected date format */
                __( 'Invalid date format for %1$s. Expected format: %2$s', 'wpuf-pro' ),
                $field_label,
                $format
            );
        }

        // Set time to midnight for date-only comparison
        $date->setTime( 0, 0, 0 );

        // Validate minDate
        $has_mintime = isset( $field_settings['mintime'] ) && strlen( trim( $field_settings['mintime'] ) ) > 0;

        if ( $has_mintime ) {
            $min_date = self::parse_min_max_date( $field_settings['mintime'] );

            if ( false !== $min_date ) {
                $min_date->setTime( 0, 0, 0 );

                if ( $date < $min_date ) {
                    return sprintf(
                        /* translators: 1: Field label, 2: Minimum date */
                        __( 'The date for %1$s must be on or after %2$s', 'wpuf-pro' ),
                        $field_label,
                        $min_date->format( $php_format )
                    );
                }
            }
        }

        // Validate maxDate
        $has_maxtime = isset( $field_settings['maxtime'] ) && strlen( trim( $field_settings['maxtime'] ) ) > 0;

        if ( $has_maxtime ) {
            $max_date = self::parse_min_max_date( $field_settings['maxtime'] );

            if ( false !== $max_date ) {
                $max_date->setTime( 0, 0, 0 );

                if ( $date > $max_date ) {
                    return sprintf(
                        /* translators: 1: Field label, 2: Maximum date */
                        __( 'The date for %1$s must be on or before %2$s', 'wpuf-pro' ),
                        $field_label,
                        $max_date->format( $php_format )
                    );
                }
            }
        }

        return '';
    }

    /**
     * Parse min/max date string into DateTime object
     *
     * @since 4.2.5
     *
     * @param string $date_string Date string in dd-mm-yyyy or dd/mm/yyyy format
     *
     * @return \DateTime|false Parsed DateTime object or false on failure
     */
    private static function parse_min_max_date( $date_string ) {
        $date_string = trim( $date_string );

        // Parse as absolute date only
        $normalized_string = str_replace( '/', '-', $date_string );
        $parts = explode( '-', $normalized_string );

        if ( count( $parts ) === 3 ) {
            $parsed = \DateTime::createFromFormat( 'j-n-Y', $normalized_string );
            if ( false === $parsed ) {
                $parsed = \DateTime::createFromFormat( 'd-m-Y', $normalized_string );
            }

            if ( false !== $parsed ) {
                $formatted_date = $parsed->format( 'j-n-Y' );
                $formatted_date_padded = $parsed->format( 'd-m-Y' );
                $normalized_input = preg_replace( '/\b0+(\d)/', '$1', $normalized_string );

                if ( $formatted_date === $normalized_input || $formatted_date_padded === $normalized_string ) {
                    $parsed->setTime( 0, 0, 0 );
                    return $parsed;
                }
            }
        }

        return false;
    }

    /**
     * Calculate age from date of birth
     *
     * @since 4.2.5
     * 
     * @since 4.2.13 Added optional reference date for age calculation
     *
     * @param string $date_of_birth Date in YYYY-MM-DD format
     * @param bool   $with_months   Whether to include months in calculation
     *
     * @return int|array|false Age in years, or array with years and months, or false on error
     */
    public static function calculate_age( $date_of_birth, $with_months = false, $reference_date = null ) {
        if ( empty( $date_of_birth ) ) {
            return false;
        }

        $dob = \DateTime::createFromFormat( 'Y-m-d', $date_of_birth );
        if ( false === $dob ) {
            return false;
        }

        // Use provided reference date or default to today
        if ( null !== $reference_date ) {
            $now = \DateTime::createFromFormat( 'Y-m-d', $reference_date );
            if ( false === $now ) {
                $now = new \DateTime();
            }
        } else {
            $now = new \DateTime();
        }

        $age = $now->diff( $dob );

        if ( $with_months ) {
            return [
                'years'  => $age->y,
                'months' => $age->m,
            ];
        }

        return $age->y;
    }

    /**
     * Format date for display based on selected format
     *
     * @since 4.2.13
     *
     * @param string $date_value Date in YYYY-MM-DD format (stored format)
     * @param string $format Datepicker format (e.g., 'dd/mm/yy')
     *
     * @return string Formatted date string
     */
    public static function format_date_for_display( $date_value, $format = 'dd/mm/yy' ) {
        if ( empty( $date_value ) ) {
            return '';
        }

        $date = \DateTime::createFromFormat( 'Y-m-d', $date_value );
        if ( false === $date ) {
            return $date_value; // Return original if parsing fails
        }

        // Convert jQuery datepicker format to PHP format
        // Handle both slash and dash separators
        $separator = strpos( $format, '/' ) !== false ? '/' : '-';
        $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );

        return $date->format( $php_format );
    }

    /**
     * Save death date and calculated age for post forms
     *
     * @since 4.2.13
     *
     * @param int   $post_id
     * @param int   $form_id
     * @param array $form_settings
     * @param array $form_fields
     *
     * @return void
     */
    public static function save_death_date_meta( $post_id, $form_id, $form_settings, $form_fields ) {
        if ( ! isset( $_POST['wpuf_death_date'] ) ) {
            return;
        }

        $death_date_input = sanitize_text_field( wp_unslash( $_POST['wpuf_death_date'] ) );

        if ( empty( $death_date_input ) ) {
            // Clear death date and calculated age if empty
            delete_post_meta( $post_id, 'wpuf_death_date' );
            delete_post_meta( $post_id, 'wpuf_deceased_age' );
            return;
        }

        // Get the format from DoB field in form
        $dob_field = null;
        foreach ( $form_fields as $field ) {
            if ( isset( $field['input_type'] ) && 'date_of_birth' === $field['input_type'] ) {
                $dob_field = $field;
                break;
            }
        }

        if ( ! $dob_field ) {
            return;
        }

        $format = isset( $dob_field['format'] ) ? $dob_field['format'] : 'dd/mm/yy';

        // Convert death date from display format to YYYY-MM-DD
        $death_date_obj = self::parse_date_from_format( $death_date_input, $format );

        if ( ! $death_date_obj ) {
            return;
        }

        $death_date_stored = $death_date_obj->format( 'Y-m-d' );

        // Save death date
        update_post_meta( $post_id, 'wpuf_death_date', $death_date_stored );

        // Calculate and save age if DoB exists
        $dob = get_post_meta( $post_id, 'wpuf_dob', true );

        if ( ! empty( $dob ) ) {
            // Convert DoB to YYYY-MM-DD if it's in display format
            $dob_obj = \DateTime::createFromFormat( 'Y-m-d', $dob );
            if ( ! $dob_obj ) {
                // Try parsing with the field format
                $dob_obj = self::parse_date_from_format( $dob, $format );
                if ( $dob_obj ) {
                    $dob = $dob_obj->format( 'Y-m-d' );
                }
            }

            if ( $dob_obj ) {
                $age = self::calculate_age( $dob, false, $death_date_stored );
                if ( false !== $age ) {
                    update_post_meta( $post_id, 'wpuf_deceased_age', $age );
                }
            }
        }
    }

    /**
     * Save death date and calculated age for user/profile forms
     *
     * Called by both wpuf_after_register (6 params) and wpuf_update_profile (4 params)
     *
     * @since 4.2.13
     *
     * @param int   $user_id
     * @param int   $form_id
     * @param array $form_settings
     *
     * @return void
     */
    public static function save_death_date_user_meta( $user_id, $form_id, $form_settings, ...$extra_params ) {
        if ( ! isset( $_POST['wpuf_death_date'] ) ) {
            return;
        }

        $death_date_input = sanitize_text_field( wp_unslash( $_POST['wpuf_death_date'] ) );

        if ( empty( $death_date_input ) ) {
            // Clear death date and calculated age if empty
            delete_user_meta( $user_id, 'wpuf_death_date' );
            delete_user_meta( $user_id, 'wpuf_deceased_age' );
            return;
        }

        // Get form fields - check both form_settings and extra_params
        $form_fields = isset( $form_settings['fields'] ) ? $form_settings['fields'] : [];

        // If fields not in form_settings, check extra_params (might be 4th parameter)
        if ( empty( $form_fields ) && ! empty( $extra_params ) && is_array( $extra_params[0] ) ) {
            $form_fields = $extra_params[0];
        }

        // Get the format from DoB field in form
        $dob_field = null;
        foreach ( $form_fields as $field ) {
            if ( isset( $field['input_type'] ) && 'date_of_birth' === $field['input_type'] ) {
                $dob_field = $field;
                break;
            }
        }

        if ( ! $dob_field ) {
            return;
        }

        $format = isset( $dob_field['format'] ) ? $dob_field['format'] : 'dd/mm/yy';

        // Convert death date from display format to YYYY-MM-DD
        $death_date_obj = self::parse_date_from_format( $death_date_input, $format );

        if ( ! $death_date_obj ) {
            return;
        }

        $death_date_stored = $death_date_obj->format( 'Y-m-d' );

        // Save death date
        update_user_meta( $user_id, 'wpuf_death_date', $death_date_stored );

        // Calculate and save age if DoB exists
        $dob = get_user_meta( $user_id, 'wpuf_dob', true );

        if ( ! empty( $dob ) ) {
            // Convert DoB to YYYY-MM-DD if it's in display format
            $dob_obj = \DateTime::createFromFormat( 'Y-m-d', $dob );
            if ( ! $dob_obj ) {
                // Try parsing with the field format
                $dob_obj = self::parse_date_from_format( $dob, $format );
                if ( $dob_obj ) {
                    $dob = $dob_obj->format( 'Y-m-d' );
                }
            }

            if ( $dob_obj ) {
                $age = self::calculate_age( $dob, false, $death_date_stored );
                if ( false !== $age ) {
                    update_user_meta( $user_id, 'wpuf_deceased_age', $age );
                }
            }
        }
    }

    /**
     * Parse date from format string
     *
     * @since 4.2.13
     *
     * @param string $date_string
     * @param string $format
     *
     * @return \DateTime|false
     */
    private static function parse_date_from_format( $date_string, $format ) {
        if ( empty( $date_string ) ) {
            return false;
        }

        // Convert jQuery datepicker format to PHP format
        $php_format = str_replace( [ 'dd', 'mm', 'yy' ], [ 'd', 'm', 'Y' ], $format );

        $date_obj = \DateTime::createFromFormat( $php_format, $date_string );

        return $date_obj;
    }
}
