<?php
/**
 * Warranty Handler
 *
 * Handles warranty creation, renewal, and management operations.
 *
 * @package WarrantyCart
 */

namespace WarrantyCart\Core;

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

/**
 * Warranty Handler Class
 */
class WarrantyHandler {

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->init_hooks();
	}

	/**
	 * Initialize hooks
	 */
	protected function init_hooks(): void {
		// Hook into payment gateway completion actions
		\add_action( 'warranty_cart_paypal_payment_completed', array( $this, 'handle_paypal_payment_completed' ), 10, 2 );
		\add_action( 'warranty_cart_stripe_payment_completed', array( $this, 'handle_stripe_payment_completed' ), 10, 2 );

		// Hook into WooCommerce order completion as fallback
		\add_action( 'woocommerce_order_status_completed', array( $this, 'handle_order_completed' ), 20, 1 );
	}

	/**
	 * Handle PayPal payment completion
	 *
	 * @param \WC_Order $order          Order object.
	 * @param array     $warranty_items Warranty items data.
	 */
	public function handle_paypal_payment_completed( \WC_Order $order, array $warranty_items ): void {
		$this->create_warranties_for_order( $order, $warranty_items, 'paypal' );
	}

	/**
	 * Handle Stripe payment completion
	 *
	 * @param \WC_Order $order          Order object.
	 * @param array     $warranty_items Warranty items data.
	 */
	public function handle_stripe_payment_completed( \WC_Order $order, array $warranty_items ): void {
		$this->create_warranties_for_order( $order, $warranty_items, 'stripe' );
	}

	/**
	 * Handle WooCommerce order completion (fallback)
	 *
	 * @param int $order_id Order ID.
	 */
	public function handle_order_completed( int $order_id ): void {
		$order = \wc_get_order( $order_id );

		if ( ! $order instanceof \WC_Order ) {
			return;
		}

		// Check if this order has already been processed
		if ( $order->get_meta( '_warranty_cart_processed', true ) ) {
			return;
		}

		// Get warranty items from order
		$warranty_items = $this->get_order_warranty_items( $order );

		if ( ! empty( $warranty_items ) ) {
			$this->create_warranties_for_order( $order, $warranty_items, 'woocommerce' );
		}
	}

	/**
	 * Create warranties for an order
	 *
	 * @param \WC_Order $order          Order object.
	 * @param array     $warranty_items Warranty items data.
	 * @param string    $source         Payment source (paypal, stripe, woocommerce).
	 */
	protected function create_warranties_for_order( \WC_Order $order, array $warranty_items, string $source ): void {
		// Prevent duplicate processing
		if ( $order->get_meta( '_warranty_cart_processed', true ) ) {
			return;
		}

		$created_warranties = array();

		foreach ( $warranty_items as $item ) {
			$warranty_id = $this->create_warranty_record( $order, $item, $source );

			if ( $warranty_id ) {
				$created_warranties[] = $warranty_id;
			}
		}

		if ( ! empty( $created_warranties ) ) {
			// Mark order as processed
			$order->update_meta_data( '_warranty_cart_processed', true );
			$order->update_meta_data( '_warranty_cart_warranties', $created_warranties );
			$order->update_meta_data( '_warranty_cart_source', $source );
			$order->save();

			// Log successful warranty creation
			$message = \sprintf(
				'Created %d warranty record(s) for order #%d via %s',
				\count( $created_warranties ),
				$order->get_id(),
				$source
			);

			\wc_get_logger()->info( $message, array( 'source' => 'warranty-cart-creation' ) );

			// Trigger action for further processing
			\do_action( 'warranty_cart_warranties_created', $order, $created_warranties, $source );
		}
	}

	/**
	 * Create a warranty record
	 *
	 * @param \WC_Order $order         Order object.
	 * @param array     $warranty_item Warranty item data.
	 * @param string    $source        Payment source.
	 *
	 * @return int|null Warranty record ID or null on failure.
	 */
	protected function create_warranty_record( \WC_Order $order, array $warranty_item, string $source ): ?int {
		try {
			// Validate required warranty item data
			if ( empty( $warranty_item['product_id'] ) || empty( $warranty_item['warranty_type'] ) ) {
				\wc_get_logger()->error(
					'Invalid warranty item data: missing product_id or warranty_type',
					array( 'source' => 'warranty-cart-creation' )
				);

				return null;
			}

			// Calculate warranty expiration date
			$expiration_date = $this->calculate_warranty_expiration(
				$warranty_item['duration'],
				$warranty_item['duration_unit']
			);

			// Validate expiration date
			if ( empty( $expiration_date ) ) {
				\wc_get_logger()->error(
					'Failed to calculate expiration date for warranty',
					array( 'source' => 'warranty-cart-creation' )
				);

				return null;
			}

			// Prepare warranty data with validation
			$warranty_data = array(
				'order_id'         => $order->get_id(),
				'customer_id'      => $order->get_customer_id(),
				'product_id'       => (int) $warranty_item['product_id'],
				'warranty_type'    => sanitize_text_field( $warranty_item['warranty_type'] ),
				'duration'         => (int) $warranty_item['duration'],
				'duration_unit'    => sanitize_text_field( $warranty_item['duration_unit'] ),
				'purchase_date'    => $order->get_date_created()->date( 'Y-m-d H:i:s' ),
				'expiration_date'  => $expiration_date,
				'purchase_price'   => (float) $warranty_item['total'],
				'currency'         => sanitize_text_field( $order->get_currency() ),
				'payment_method'   => sanitize_text_field( $order->get_payment_method() ),
				'status'           => 'active',
				'source'           => sanitize_text_field( $source ),
				'coverage_details' => sanitize_textarea_field( $warranty_item['product']->get_meta( '_warranty_coverage_details', true ) ),
				'created_at'       => \current_time( 'mysql' ),
			);

			// Insert warranty record
			global $wpdb;
			$table_name = $wpdb->prefix . 'warranty_cart_warranties';

			$result = $wpdb->insert(
				$table_name,
				$warranty_data,
				array(
					'%d', // order_id
					'%d', // customer_id
					'%d', // product_id
					'%s', // warranty_type
					'%d', // duration
					'%s', // duration_unit
					'%s', // purchase_date
					'%s', // expiration_date
					'%f', // purchase_price
					'%s', // currency
					'%s', // payment_method
					'%s', // status
					'%s', // source
					'%s', // coverage_details
					'%s', // created_at
				)
			);

			if ( false === $result ) {
				\wc_get_logger()->error(
					'Failed to create warranty record for order #' . $order->get_id(),
					array( 'source' => 'warranty-cart-creation' )
				);

				return null;
			}

			$warranty_id = $wpdb->insert_id;

			// Trigger action for individual warranty creation
			\do_action( 'warranty_cart_warranty_created', $warranty_id, $warranty_data, $order );

			return $warranty_id;
		} catch ( \Exception $e ) {
			\wc_get_logger()->error(
				'Exception creating warranty record: ' . $e->getMessage(),
				array( 'source' => 'warranty-cart-creation' )
			);

			return null;
		}
	}

	/**
	 * Calculate warranty expiration date
	 *
	 * @param int    $duration Duration value.
	 * @param string $unit     Duration unit (days, months, years).
	 *
	 * @return string Expiration date in Y-m-d format.
	 */
	protected function calculate_warranty_expiration( int $duration, string $unit ): string {
		// Validate inputs
		if ( $duration < 1 ) {
			$duration = 1;
		}

		$valid_units = array( 'days', 'months', 'years' );
		if ( ! in_array( $unit, $valid_units, true ) ) {
			$unit = 'years';
		}

		// Use DateTime for accurate calculations
		try {
			$now = new \DateTime( 'now', wp_timezone() );

			switch ( $unit ) {
				case 'days':
					$now->add( new \DateInterval( 'P' . $duration . 'D' ) );
					break;
				case 'months':
					$now->add( new \DateInterval( 'P' . $duration . 'M' ) );
					break;
				case 'years':
				default:
					$now->add( new \DateInterval( 'P' . $duration . 'Y' ) );
					break;
			}

			return $now->format( 'Y-m-d' );
		} catch ( \Exception $e ) {
			// Fallback to strtotime with WordPress timezone
			$timestamp = \strtotime( "+{$duration} {$unit}", \time() );
			if ( $timestamp ) {
				return \wp_date( 'Y-m-d', $timestamp );
			}

			// Ultimate fallback: 1 year from now
			return \wp_date( 'Y-m-d', \strtotime( '+1 year', \time() ) );
		}
	}

	/**
	 * Get warranty items from order
	 *
	 * @param \WC_Order $order Order object.
	 *
	 * @return array Array of warranty items.
	 */
	protected function get_order_warranty_items( \WC_Order $order ): array {
		$warranty_items = array();

		foreach ( $order->get_items( 'line_item' ) as $item ) {
			$product = $item->get_product();

			if ( ! $product ) {
				continue;
			}

			// Check if this is a warranty product using meta fields
			$product_status = $product->get_meta( '_warranty_cart_product_status', true );
			$warranty_type  = $product->get_meta( '_warranty_cart_product_type', true );

			if ( 'enabled' === $product_status && ! empty( $warranty_type ) ) {
				// Validate warranty configuration
				$duration      = (int) $product->get_meta( '_warranty_cart_duration', true );
				$duration_unit = $product->get_meta( '_warranty_cart_duration_unit', true );

				// Ensure valid duration (minimum 1)
				if ( $duration < 1 ) {
					$duration = 1;
				}

				// Ensure valid duration unit
				$valid_units = array( 'days', 'months', 'years' );
				if ( ! in_array( $duration_unit, $valid_units, true ) ) {
					$duration_unit = 'years';
				}

				$warranty_items[] = array(
					'product'       => $product,
					'order_item'    => $item,
					'product_id'    => $product->get_id(),
					'product_name'  => $product->get_name(),
					'quantity'      => $item->get_quantity(),
					'total'         => $item->get_total(),
					'warranty_type' => $warranty_type,
					'duration'      => $duration,
					'duration_unit' => $duration_unit,
				);
			}
		}

		return $warranty_items;
	}

	/**
	 * Renew a warranty
	 *
	 * @param int $warranty_id Warranty ID to renew.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function renew_warranty( int $warranty_id ): bool {
		global $wpdb;

		$table_name = $wpdb->prefix . 'warranty_cart_warranties';

		// Validate warranty ID
		if ( 0 >= $warranty_id ) {
			\wc_get_logger()->error(
				'Invalid warranty ID provided for renewal',
				array( 'source' => 'warranty-cart-renewal' )
			);

			return false;
		}

		// Get current warranty data
		$warranty = $wpdb->get_row(
			$wpdb->prepare(
				'SELECT * FROM %s WHERE id = %d',
				$table_name,
				$warranty_id
			)
		);

		if ( ! $warranty ) {
			\wc_get_logger()->error(
				\sprintf( 'Warranty #%d not found for renewal', $warranty_id ),
				array( 'source' => 'warranty-cart-renewal' )
			);

			return false;
		}

		// Check if warranty can be renewed (not already expired beyond renewal period)
		if ( 'expired' === $warranty->status ) {
			$current_date     = \current_time( 'Y-m-d' );
			$renewal_deadline = \wp_date( 'Y-m-d', \strtotime( $warranty->expiration_date . ' +30 days' ) );

			if ( $current_date > $renewal_deadline ) {
				\wc_get_logger()->error(
					\sprintf( 'Warranty #%d cannot be renewed - expired too long ago', $warranty_id ),
					array( 'source' => 'warranty-cart-renewal' )
				);

				return false;
			}
		}

		// Calculate new expiration date
		$new_expiration = $this->calculate_warranty_expiration(
			(int) $warranty->duration,
			$warranty->duration_unit
		);

		if ( empty( $new_expiration ) ) {
			\wc_get_logger()->error(
				\sprintf( 'Failed to calculate new expiration date for warranty #%d', $warranty_id ),
				array( 'source' => 'warranty-cart-renewal' )
			);

			return false;
		}

		// Update warranty record
		$result = $wpdb->update(
			$table_name,
			array(
				'expiration_date'   => $new_expiration,
				'status'            => 'active',
				'renewal_count'     => (int) $warranty->renewal_count + 1,
				'last_renewal_date' => \current_time( 'mysql' ),
				'updated_at'        => \current_time( 'mysql' ),
			),
			array( 'id' => $warranty_id ),
			array( '%s', '%s', '%d', '%s', '%s' ),
			array( '%d' )
		);

		if ( false !== $result ) {
			// Trigger renewal action
			\do_action( 'warranty_cart_warranty_renewed', $warranty_id, $warranty, $new_expiration );

			\wc_get_logger()->info(
				\sprintf( 'Warranty #%d renewed successfully to %s', $warranty_id, $new_expiration ),
				array( 'source' => 'warranty-cart-renewal' )
			);

			return true;
		}

		\wc_get_logger()->error(
			\sprintf( 'Database update failed for warranty #%d renewal', $warranty_id ),
			array( 'source' => 'warranty-cart-renewal' )
		);

		return false;
	}
}
