<?php

namespace Devnet\EBC\Includes;


if (!defined('ABSPATH')) {
    exit;
}


class Helper
{

    public static function get_booked_dates($product_id = null)
    {

        // Check if a product ID is provided, or try to get it from the global $product
        if ($product_id) {
            $product = wc_get_product($product_id);
        } else {
            global $product;

            if (!is_product() || !$product) {
                return;
            }

            $product_id = $product->get_id();
            $product = wc_get_product($product_id);
        }

        if (!$product) {
            return;
        }

        // Retrieve booked dates from product meta
        $dates = (array)$product->get_meta('_ebc_booked_dates');

        return self::sort_booked_dates($dates);
    }

    /**
     * Sort booked dates by "from" date, then by "to" date (ascending).
     *
     */
    public static function sort_booked_dates(array $booked_dates): array
    {
        uasort($booked_dates, function ($a, $b) {
            $from_a = strtotime($a['from'] ?? '9999-12-31');
            $from_b = strtotime($b['from'] ?? '9999-12-31');

            // Compare "from" dates first
            if ($from_a !== $from_b) {
                return ($from_a < $from_b) ? -1 : 1;
            }

            // If "from" is the same, compare "to" dates
            $to_a = strtotime($a['to'] ?? '9999-12-31');
            $to_b = strtotime($b['to'] ?? '9999-12-31');

            if ($to_a === $to_b) {
                return 0;
            }

            return ($to_a < $to_b) ? -1 : 1;
        });

        return $booked_dates;
    }


    /**
     * Clean booked dates array so there are no duplicates or overlaps.
     *
     */
    public static function clean_booked_dates(array $booked_dates): array
    {
        $normalized = [];

        // Step 1: normalize and strip order_id (calendar doesn’t need it)
        foreach ($booked_dates as $row) {
            $from = $row['from'] ?? null;
            $to   = $row['to'] ?? $from;

            if (!$from) {
                continue;
            }

            if ($to < $from) {
                [$from, $to] = [$to, $from]; // swap if reversed
            }

            $normalized[] = ['from' => $from, 'to' => $to];
        }

        if (empty($normalized)) {
            return [];
        }

        // Step 2: sort by from, then to
        usort($normalized, function ($a, $b) {
            if ($a['from'] === $b['from']) {
                return strcmp($a['to'], $b['to']);
            }
            return strcmp($a['from'], $b['from']);
        });

        // Step 3: merge overlaps and duplicates
        $merged = [];
        foreach ($normalized as $range) {
            if (empty($merged)) {
                $merged[] = $range;
                continue;
            }

            $last = &$merged[count($merged) - 1];

            // overlap or contiguous
            if ($range['from'] <= $last['to']) {
                if ($range['to'] > $last['to']) {
                    $last['to'] = $range['to']; // extend
                }
            } else {
                $merged[] = $range; // new block
            }
        }

        return $merged;
    }


    public static function is_bookable($product = null)
    {
        if (is_a($product, 'WC_Product')) {
            return $product->get_meta('_ebc_bookable') === 'yes';
        }

        if (is_numeric($product)) {
            return get_post_meta($product, '_ebc_bookable', true) === 'yes';
        }

        global $post;

        if ($post && isset($post->ID)) {
            return get_post_meta($post->ID, '_ebc_bookable', true) === 'yes';
        }

        return false;
    }


    public static function get_option($name = '', $group = '')
    {
        $saved_options = DEVNET_EBC_OPTIONS;
        $is_multilingual = $saved_options['general']['multilingual'] ?? false;

        $multilingual_fields = [
            'title',
            'button_text',
        ];

        $option = '';

        if (!$name && !$group) {

            $all_options = [];

            foreach ($saved_options as $group_name => $group_options) {

                $group_defaults = Defaults::{$group_name}();

                foreach ($group_defaults as $name => $value) {
                    $option_value = $group_options[$name] ?? $value;

                    if ($is_multilingual && in_array($name, $multilingual_fields)) {
                        $option_value = $value;
                    }

                    $all_options[$group_name][$name] = $option_value;
                }
            }

            $option = $all_options;
        } else {
            $option = $saved_options[$group][$name] ?? Defaults::{$group}($name);

            if ($is_multilingual && in_array($name, $multilingual_fields)) {
                $option = Defaults::{$group}($name);
            }
        }

        return $option;
    }

    /**
     * Extracts the start and end dates from a date range string.
     *
     * @param string $date_range The date range string in 'Y-m-d to Y-m-d' format.
     * @return array|null Returns an array with 'from' and 'to' dates or null if invalid.
     */
    public static function extract_dates_from_range($date_range)
    {
        preg_match_all('/\d{4}\-\d{2}\-\d{2}/', $date_range, $matches);

        if (isset($matches[0]) && count($matches[0]) > 0) {
            $booked_from = $matches[0][0] ?? ''; // First date (start)
            $booked_to   = $matches[0][1] ?? $booked_from; // Use same if no second date

            return [
                'from' => $booked_from,
                'to'   => $booked_to,
            ];
        }

        return null;
    }

    /**
     * Calculate booking quantity based on calculation mode.
     *
     * @param string $date_range
     * @return int
     */
    public static function calculate_booking_quantity($date_range)
    {

        $options = DEVNET_EBC_OPTIONS['product'] ?? [];

        $mode = $options['booking_calculation_mode']
            ?? Defaults::calendar('booking_calculation_mode')
            ?? 'nights';

        // Extract dates using the extract_dates_from_range method
        $dates = self::extract_dates_from_range($date_range);

        // If dates are invalid, default to 1 day
        if (!$dates || !isset($dates['from']) || !isset($dates['to'])) {
            return 1;
        }

        if ($mode === 'days') {
            return self::calculate_selected_days($dates);
        }

        // default + fallback (nights mode)
        return self::calculate_days_between_dates($dates);
    }

    /**
     * Calculates the number of selected days in a date range (inclusive).
     *
     * @param array $dates Array with 'from' and 'to' keys containing date strings.
     * @return int Returns the number of selected days (inclusive). Minimum is 1 day.
     */
    public static function calculate_selected_days($dates)
    {
        // If dates are invalid, default to 1 day
        if (!$dates || !isset($dates['from']) || !isset($dates['to'])) {
            return 1;
        }

        // If from and to dates are the same, return 1
        if ($dates['from'] === $dates['to']) {
            return 1;
        }

        // For different dates, calculate nights and add 1
        return self::calculate_days_between_dates($dates) + 1;
    }

    /**
     * Calculates the number of nights between two dates (difference).
     *
     * @param array $dates Array with 'from' and 'to' keys containing date strings.
     * @return int Returns the number of nights between the dates. Minimum is 1 night.
     */
    public static function calculate_days_between_dates($dates)
    {
        // Convert 'from' and 'to' dates to timestamps
        $from_timestamp = strtotime($dates['from']);
        $to_timestamp = strtotime($dates['to']);

        // Calculate the difference in days
        $time_difference = $to_timestamp - $from_timestamp;
        $days = floor($time_difference / (60 * 60 * 24));

        return max(1, $days); // Ensure the minimum is 1 day
    }
}
