<?php

namespace Devnet\EBC\Public;

use Devnet\EBC\Includes\Defaults;
use Devnet\EBC\Includes\Helper;


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


class PublicSide
{

	private $plugin_name;
	private $version;
	private $double_bookings = false;

	public function __construct($plugin_name, $version)
	{

		$this->plugin_name = $plugin_name;
		$this->version     = $version;

		$this->double_bookings = DEVNET_EBC_OPTIONS['product']['double_bookings'] ?? false;

		$general_opt = DEVNET_EBC_OPTIONS['general'] ?? [];
		$only_logged_users = $general_opt['only_logged_users'] ?? false;

		if ($only_logged_users && !is_user_logged_in()) {
			return;
		}

		add_action('wp_enqueue_scripts', [$this, 'enqueue_styles']);
		add_action('wp_enqueue_scripts', [$this, 'enqueue_scripts']);

		add_action('woocommerce_before_add_to_cart_button', [$this, 'date_fields']);

		add_filter('woocommerce_product_single_add_to_cart_text', [$this, 'add_to_cart_text'], 10, 2);
		add_filter('woocommerce_product_add_to_cart_text', [$this, 'add_to_cart_text'], 10, 2);

		add_filter('woocommerce_is_sold_individually', [$this, 'disable_quantity_field'], 10, 2);

		add_filter('woocommerce_add_to_cart_validation', [$this, 'product_validation'], 10, 3);
		add_filter('woocommerce_add_cart_item_data', [$this, 'product_cart_item_data'], 10, 2);
		add_action('woocommerce_before_calculate_totals', [$this, 'update_cart_quantity_based_on_dates']);

		add_filter('woocommerce_get_item_data', [$this, 'product_display_cart'], 10, 2);
		add_action('woocommerce_checkout_create_order_line_item', [$this, 'product_order_item_meta'], 10, 4);
		add_filter('woocommerce_order_item_display_meta_key', [$this, 'meta_key_display_text'], 20, 3);
		add_filter('woocommerce_order_item_display_meta_value', [$this, 'display_meta_value'], 10, 2);

		add_action('woocommerce_order_status_completed', [$this, 'save_booked_dates_on_product'], 10, 3);
		add_action('woocommerce_order_status_processing', [$this, 'save_booked_dates_on_product'], 10, 3);
		add_action('woocommerce_order_status_cancelled', [$this, 'unbook_dates_on_canceled_order'], 10, 3);
	}

	public function enqueue_styles()
	{

		if (!is_product()) {
			return;
		}

		wp_enqueue_style($this->plugin_name, plugin_dir_url(__DIR__) . 'assets/build/public.css', [], $this->version, 'all');

		$theme = Helper::get_option('theme', 'calendar');

		if ($theme) {
			wp_enqueue_style($this->plugin_name . '-flatpickr-theme', plugin_dir_url(__DIR__) . 'assets/vendor/flatpickr/themes/' . esc_attr($theme) . '.css', [], $this->version, 'all');
		}
	}

	public function enqueue_scripts()
	{

		if (!is_product()) {
			return;
		}

		global $post;
		$product_id = $post->ID;
		$booked_dates = Helper::get_booked_dates($product_id);


		if ($this->double_bookings) {
			$booked_dates = [];
		} else {
			// Make sure there are no overlapping dates.
			$booked_dates = Helper::clean_booked_dates($booked_dates);
		}

		$script_asset_path = plugin_dir_url(__DIR__) . 'assets/build/public.asset.php';
		$script_info       = file_exists($script_asset_path)
			? include $script_asset_path
			: ['dependencies' => ['jquery'], 'version' => $this->version];

		wp_enqueue_script(
			$this->plugin_name,
			plugin_dir_url(__DIR__) . 'assets/build/public.js',
			$script_info['dependencies'],
			$script_info['version'],
			true
		);



		wp_localize_script($this->plugin_name, 'devnet_ebc_script_data', [
			'ajaxurl'      => admin_url('admin-ajax.php'),
			'nonce'        => wp_create_nonce('easy-booking-calendar-nonce'),
			'booked_dates' => $booked_dates,
			'options'	   => DEVNET_EBC_OPTIONS['calendar']
		]);

		$locale = Helper::get_option('locale', 'calendar');

		if ($locale) {

			wp_enqueue_script(
				$this->plugin_name . '-flatpickr-locale',
				plugin_dir_url(__DIR__) . 'assets/vendor/flatpickr/l10n/' . esc_attr($locale) . '.js',
				[],
				$this->version,
				true
			);
		}
	}



	public function date_fields()
	{
		global $product;

		if (!Helper::is_bookable($product)) {
			return;
		}

		$primary_color = Helper::get_option('primary_color', 'calendar');
		$title = Helper::get_option('title', 'calendar');

		$styles = '--ebc--color-primary:' . $primary_color . ';';

		echo '<div id="ebc-wrapper" style="' . esc_attr($styles) . '">';
		echo '<div class="ebc-inner">';
		echo '<h3>' . esc_html($title) . '</h3>';
		echo '<input type="date" id="ebc-date-field" name="ebc_date_range" placeholder="' . esc_html__('Pick a date', 'easy-booking-calendar') . '" />';
		echo '</div>';
		echo '</div>';
	}

	public function add_to_cart_text($text, $product)
	{

		if (Helper::is_bookable($product)) {

			$button_text = Helper::get_option('button_text', 'product');

			$text = $button_text ? $button_text : Defaults::product('button_text');
		}

		return $text;
	}

	public function disable_quantity_field($sold_individually, $product)
	{

		$disable_quantity = Helper::get_option('disable_quantity', 'product');

		if (Helper::is_bookable($product) && $disable_quantity) {
			$sold_individually = true;
		}

		return $sold_individually;
	}

	/**
	 * Throw error if custom input field empty
	 */
	public function product_validation($passed, $product_id, $qty)
	{

		if (isset($_POST['ebc_date_range']) && sanitize_text_field(wp_unslash($_POST['ebc_date_range'])) == '') {

			$error_notice = esc_html__('Date is required!', 'easy-booking-calendar');

			wc_add_notice($error_notice, 'error');

			$passed = false;
		}

		return $passed;
	}

	/**
	 * Save custom input field value into cart item data
	 */
	public function product_cart_item_data($cart_item_data, $product_id)
	{

		if (isset($_POST['ebc_date_range'])) {

			$product = wc_get_product($product_id);

			if (Helper::is_bookable($product)) {

				$cart_item_data['ebc_date_range'] = sanitize_text_field(wp_unslash($_POST['ebc_date_range']));

				$days = Helper::calculate_booking_quantity($cart_item_data['ebc_date_range']);

				$cart_item_data['days'] = $days;
			}
		}

		return $cart_item_data;
	}

	public function update_cart_quantity_based_on_dates($cart)
	{
		foreach ($cart->get_cart() as $cart_item_key => $cart_item) {

			if (isset($cart_item['days'])) {

				$days = intval($cart_item['days']);

				if ($days > 0) {
					// Must be `false` to avoid infinite loop.
					$cart->set_quantity($cart_item_key, $days, false);
				}
			}
		}
	}

	/**
	 * Display custom input field value @ Cart
	 */
	public function product_display_cart($data, $cart_item)
	{

		if (isset($cart_item['ebc_date_range'])) {

			$data[] = [
				'name'  => esc_html__('Date', 'easy-booking-calendar'),
				'value' => sanitize_text_field($this->format_date_range($cart_item['ebc_date_range']))
			];
		}

		return $data;
	}

	/**
	 * Save custom input field value into order item meta
	 */
	public function product_order_item_meta($item, $cart_item_key, $values, $order)
	{

		if (empty($values['ebc_date_range'])) {
			return;
		}

		$item->add_meta_data('ebc_date_range', $values['ebc_date_range']);
	}

	/**
	 * Order item meta key display
	 */
	public function meta_key_display_text($display_key, $meta, $item)
	{

		// Change displayed label for specific order item meta key
		if ($item->get_type() === 'line_item' && $meta->key === 'ebc_date_range') {
			$display_key = esc_html__('Date', 'easy-booking-calendar');
		}

		return $display_key;
	}

	public function display_meta_value($value, $meta)
	{
		if ($meta->key === 'ebc_date_range') {

			$value = $this->format_date_range($value);
		}
		return $value;
	}

	/**
	 * Saves booked dates to product meta when the order is completed.
	 */
	public function save_booked_dates_on_product($order_id, $order = null, $status_transition = null)
	{
		// Get the order object if not provided
		if (!$order) {
			$order = wc_get_order($order_id);
		}

		// Loop through each item in the order
		foreach ($order->get_items() as $item_id => $item) {
			$product_id = $item->get_product_id();
			$date_range = wc_get_order_item_meta($item_id, 'ebc_date_range', true);

			if ($date_range) {
				$this->save_dates_if_not_overlapping([
					'product_id' => $product_id,
					'order_id'   => $order_id,
					'date_range' => $date_range,
				]);
			}
		}
	}

	/**
	 * Unbooks dates from the product meta when the order is canceled.
	 */
	public function unbook_dates_on_canceled_order($order_id, $order = null, $status_transition = null)
	{
		// Get the order object if not provided
		if (!$order) {
			$order = wc_get_order($order_id);
		}

		foreach ($order->get_items() as $item_id => $item) {
			$product_id = $item->get_product_id();
			$date_range = wc_get_order_item_meta($item_id, 'ebc_date_range', true);

			if ($date_range) {
				$this->remove_dates_from_product([
					'product_id' => $product_id,
					'order_id'   => $order_id,
					'date_range' => $date_range,
				]);
			}
		}
	}

	private function format_date_range($range, $date_format = '')
	{
		$formatted_range = $range;

		if (!$date_format) {
			$options = DEVNET_EBC_OPTIONS['calendar'] ?? [];
			$date_format = $options['date_format'] ?? Defaults::calendar('date_format');
		}

		// Use the function to extract dates from the range
		$dates = Helper::extract_dates_from_range($range);

		if ($dates) {
			$from = date_i18n($date_format, strtotime($dates['from']));
			$to   = date_i18n($date_format, strtotime($dates['to']));

			// Format the display as "From - To"
			$formatted_range = sprintf('%s - %s', $from, $to);
		}

		return $formatted_range;
	}

	/**
	 * Saves the booked dates to the product if they don't overlap with existing bookings.
	 */
	private function save_dates_if_not_overlapping($args = [])
	{
		$product_id = $args['product_id'] ?? null;
		$order_id   = $args['order_id'] ?? null;
		$date_range = $args['date_range'] ?? null;

		$product = wc_get_product($product_id);
		if (!$product) {
			return;
		}

		$dates = Helper::extract_dates_from_range($date_range);
		$booked_from = $dates['from'] ?? '';
		$booked_to   = $dates['to'] ?? '';

		$current_date = gmdate('Y-m-d');
		$existing_booked_dates = $product->get_meta('_ebc_booked_dates');

		// Initialize the array if it's empty
		if (!is_array($existing_booked_dates)) {
			$existing_booked_dates = [];
		}

		// Remove bookings where 'to' date is in the past
		$existing_booked_dates = array_filter($existing_booked_dates, function ($booking) use ($current_date) {
			return strtotime($booking['to']) >= strtotime($current_date);
		});

		// Reindex the array to reset keys
		$existing_booked_dates = array_values($existing_booked_dates);


		// Check for overlapping bookings
		if (!$this->is_overlapping($existing_booked_dates, $booked_from, $booked_to)) {
			// Add the new booked date range
			$existing_booked_dates[] = [
				'from'     => $booked_from,
				'to'       => $booked_to,
				'order_id' => $order_id,
			];

			$product->update_meta_data('_ebc_booked_dates', $existing_booked_dates);
			$product->save();
		}
	}

	/**
	 * Remove booked dates for an order.
	 * - If any entries have matching order_id → remove only those.
	 * - Else → remove legacy entries (without order_id) that match date_range.
	 */
	private function remove_dates_from_product($args = [])
	{
		$product_id = $args['product_id'] ?? null;
		$order_id   = isset($args['order_id']) ? (int) $args['order_id'] : null;
		$date_range = $args['date_range'] ?? null;

		if (!$product_id || $order_id === null) {
			return;
		}

		$product = wc_get_product($product_id);
		if (!$product) {
			return;
		}

		$booked = $product->get_meta('_ebc_booked_dates');
		if (!is_array($booked)) {
			$booked = [];
		}

		// Check if there are any rows with this order_id
		$has_matching_order_rows = false;
		foreach ($booked as $row) {
			if (isset($row['order_id']) && (int) $row['order_id'] === $order_id) {
				$has_matching_order_rows = true;
				break;
			}
		}

		$filtered = $booked;

		if ($has_matching_order_rows) {
			// Remove only rows with this order_id
			$filtered = array_values(array_filter($booked, function ($row) use ($order_id) {
				return !(isset($row['order_id']) && (int) $row['order_id'] === $order_id);
			}));
		} else {

			// Legacy path: remove by exact from/to match, only for rows WITHOUT order_id
			$from = $to = '';
			if ($date_range) {
				$parsed = Helper::extract_dates_from_range($date_range);
				$from   = $parsed['from'] ?? '';
				$to     = $parsed['to']   ?? '';
			}

			if ($from && $to) {
				$filtered = array_values(array_filter($booked, function ($row) use ($from, $to) {
					$is_legacy = !isset($row['order_id']);
					$rf = $row['from'] ?? '';
					$rt = $row['to']   ?? '';
					return !($is_legacy && $rf === $from && $rt === $to);
				}));
			}
		}

		// Save back (or return $filtered if you want the caller to save)
		$product->update_meta_data('_ebc_booked_dates', $filtered);
		$product->save();
	}


	/**
	 * Checks if the new booking dates overlap with existing ones.
	 */
	private function is_overlapping($existing_booked_dates, $new_from, $new_to)
	{

		if ($this->double_bookings) {
			return false; // No overlapping
		}

		$new_from_time = strtotime($new_from);
		$new_to_time = strtotime($new_to);

		foreach ($existing_booked_dates as $existing_booking) {
			$existing_from_time = strtotime($existing_booking['from']);
			$existing_to_time = strtotime($existing_booking['to']);

			if (($new_from_time >= $existing_from_time && $new_from_time <= $existing_to_time) ||
				($new_to_time >= $existing_from_time && $new_to_time <= $existing_to_time) ||
				($new_from_time <= $existing_from_time && $new_to_time >= $existing_to_time)
			) {
				return true; // Overlapping found
			}
		}

		return false; // No overlapping
	}
}
