<?php
/**
 * Payment manager - orchestrates deposit, balance, and security deposit
 *
 * @package WahraRentalsBookings
 */

defined('ABSPATH') || exit;

/**
 * Payment manager class
 */
class WAHRB_Payment_Manager {

    /**
     * Single instance
     *
     * @var WAHRB_Payment_Manager|null
     */
    private static ?WAHRB_Payment_Manager $instance = null;

    /**
     * Get single instance
     *
     * @return WAHRB_Payment_Manager
     */
    public static function instance(): WAHRB_Payment_Manager {
        if (is_null(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

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

    /**
     * Initialize hooks
     */
    private function init_hooks(): void {
        // Order creation
        add_action('woocommerce_checkout_order_processed', [$this, 'process_booking_order'], 10, 3);

        // Order status changes
        add_action('woocommerce_order_status_completed', [$this, 'on_order_completed']);
        add_action('woocommerce_order_status_processing', [$this, 'on_order_processing']);

        // Cart display
        add_filter('woocommerce_cart_item_name', [$this, 'cart_item_name'], 10, 3);
        add_filter('woocommerce_order_item_name', [$this, 'order_item_name'], 10, 3);
    }

    /**
     * Create order #1 for booking (deposit + security deposit)
     *
     * @param WAHRB_Booking $booking Booking object
     * @return WC_Order|WP_Error
     */
    public function create_deposit_order(WAHRB_Booking $booking) {
        $schedule = $booking->get_payment_schedule();
        if (!$schedule) {
            return new WP_Error('no_schedule', __('Payment schedule not found', 'wahra-rentals-bookings'));
        }

        // Create order
        $order = wc_create_order([
            'status' => 'pending',
            'customer_id' => $booking->get('customer_id'),
        ]);

        if (is_wp_error($order)) {
            return $order;
        }

        // Add deposit product
        if ($schedule['deposit_enabled'] && $schedule['deposit_amount_final'] > 0) {
            $deposit_product_id = get_option('wahrb_deposit_product_id');
            if ($deposit_product_id) {
                $order->add_product(
                    wc_get_product($deposit_product_id),
                    1,
                    [
                        'subtotal' => $schedule['deposit_amount_final'],
                        'total' => $schedule['deposit_amount_final'],
                    ]
                );
            } else {
                // Add as fee
                $fee = new WC_Order_Item_Fee();
                $fee->set_name(__('Booking deposit', 'wahra-rentals-bookings'));
                $fee->set_amount($schedule['deposit_amount_final']);
                $fee->set_total($schedule['deposit_amount_final']);
                $order->add_item($fee);
            }
        }

        // Add security deposit
        if ($schedule['security_deposit_enabled'] && $schedule['security_deposit_amount_final'] > 0) {
            $security_product_id = get_option('wahrb_security_product_id');
            if ($security_product_id) {
                $order->add_product(
                    wc_get_product($security_product_id),
                    1,
                    [
                        'subtotal' => $schedule['security_deposit_amount_final'],
                        'total' => $schedule['security_deposit_amount_final'],
                    ]
                );
            } else {
                $fee = new WC_Order_Item_Fee();
                $fee->set_name(__('Security deposit (refundable)', 'wahra-rentals-bookings'));
                $fee->set_amount($schedule['security_deposit_amount_final']);
                $fee->set_total($schedule['security_deposit_amount_final']);
                $order->add_item($fee);
            }
        }

        // Set order meta
        $order->add_meta_data('_wahrb_booking_id', $booking->get_id());
        $order->add_meta_data('_wahrb_order_type', 'deposit');
        $order->add_meta_data('_wahrb_booking_number', $booking->get_booking_number());

        // Set customer details
        $order->set_billing_first_name($booking->get('customer_name'));
        $order->set_billing_email($booking->get('customer_email'));
        $order->set_billing_phone($booking->get('customer_phone'));

        // Calculate totals
        $order->calculate_totals();
        $order->save();

        // Update booking with order ID
        global $wpdb;
        $db = WAHRB_Database::instance();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->update(
            $db->table('bookings'),
            ['customer_order_id' => $order->get_id()],
            ['booking_id' => $booking->get_id()]
        );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->update(
            $db->table('payment_schedule'),
            [
                'deposit_order_id' => $order->get_id(),
                'deposit_status' => 'pending',
            ],
            ['booking_id' => $booking->get_id()]
        );

        return $order;
    }

    /**
     * Create order #2 for balance
     *
     * @param WAHRB_Booking $booking Booking object
     * @return WC_Order|WP_Error|null
     */
    public function create_balance_order(WAHRB_Booking $booking) {
        $schedule = $booking->get_payment_schedule();

        if (!$schedule || !$schedule['balance_enabled'] || $schedule['balance_amount_final'] <= 0) {
            return null;
        }

        // Create order
        $order = wc_create_order([
            'status' => 'pending',
            'customer_id' => $booking->get('customer_id'),
        ]);

        if (is_wp_error($order)) {
            return $order;
        }

        // Add balance product
        $balance_product_id = get_option('wahrb_balance_product_id');
        if ($balance_product_id) {
            $order->add_product(
                wc_get_product($balance_product_id),
                1,
                [
                    'subtotal' => $schedule['balance_amount_final'],
                    'total' => $schedule['balance_amount_final'],
                ]
            );
        } else {
            $fee = new WC_Order_Item_Fee();
            /* translators: %s: booking number */
            $fee->set_name(sprintf(__('Booking balance #%s', 'wahra-rentals-bookings'), $booking->get_booking_number()));
            $fee->set_amount($schedule['balance_amount_final']);
            $fee->set_total($schedule['balance_amount_final']);
            $order->add_item($fee);
        }

        // Set order meta
        $order->add_meta_data('_wahrb_booking_id', $booking->get_id());
        $order->add_meta_data('_wahrb_order_type', 'balance');
        $order->add_meta_data('_wahrb_booking_number', $booking->get_booking_number());
        $order->add_meta_data('_wahrb_order1_id', $schedule['deposit_order_id']);
        $order->add_meta_data('_wahrb_balance_due_at', $schedule['balance_due_at']);
        $order->add_meta_data('_wahrb_allow_cod', $schedule['balance_allow_cod']);

        // Set customer details
        $order->set_billing_first_name($booking->get('customer_name'));
        $order->set_billing_email($booking->get('customer_email'));
        $order->set_billing_phone($booking->get('customer_phone'));

        // Calculate totals
        $order->calculate_totals();
        $order->save();

        // Update booking with order ID
        global $wpdb;
        $db = WAHRB_Database::instance();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->update(
            $db->table('bookings'),
            ['customer_order2_id' => $order->get_id()],
            ['booking_id' => $booking->get_id()]
        );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $wpdb->update(
            $db->table('payment_schedule'),
            [
                'balance_order_id' => $order->get_id(),
                'balance_status' => 'pending',
            ],
            ['booking_id' => $booking->get_id()]
        );

        // Send email to customer
        do_action('wahrb_balance_order_created', $order, $booking);

        return $order;
    }

    /**
     * Process booking during checkout
     *
     * @param int $order_id Order ID
     * @param array $posted_data Posted data
     * @param WC_Order $order Order object
     */
    public function process_booking_order(int $order_id, array $posted_data, WC_Order $order): void {
        // Check if this order has booking items
        foreach ($order->get_items() as $item) {
            $hold_id = $item->get_meta('_wahrb_hold_id');
            if (!$hold_id) {
                continue;
            }

            $hold = new WAHRB_Hold($hold_id);
            if (!$hold->is_valid()) {
                // Hold expired, but let the order continue
                // We'll check availability again
                continue;
            }

            // Get booking data from hold
            $product_id = $item->get_product_id();
            $variation_id = $item->get_variation_id();
            $start_date = $item->get_meta('_wahrb_start_date');
            $end_date = $item->get_meta('_wahrb_end_date');
            $qty = $item->get_meta('_wahrb_qty') ?: 1;

            // Create booking
            $product = wc_get_product($product_id);
            $vendor_id = get_post_field('post_author', $product_id);

            $booking = WAHRB_Booking::create([
                'vendor_id' => $vendor_id,
                'product_id' => $product_id,
                'variation_id' => $variation_id ?: null,
                'customer_id' => $order->get_customer_id(),
                'start_dt' => $start_date,
                'end_dt' => $end_date,
                'qty' => $qty,
                'customer_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
                'customer_email' => $order->get_billing_email(),
                'customer_phone' => $order->get_billing_phone(),
                'booking_mode' => get_post_meta($product_id, '_wahrb_booking_mode', true) ?: 'day',
            ]);

            if (is_wp_error($booking)) {
                // Log error but continue
                wc_add_notice($booking->get_error_message(), 'error');
                continue;
            }

            // Convert hold to booking
            $hold->convert_to_booking($booking->get_id(), $order_id);

            // Store booking ID in order meta
            $order->add_meta_data('_wahrb_booking_id', $booking->get_id());
            $order->add_meta_data('_wahrb_booking_number', $booking->get_booking_number());
            $order->add_meta_data('_wahrb_order_type', 'deposit');

            // Update booking with order ID
            global $wpdb;
            $db = WAHRB_Database::instance();

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('bookings'),
                ['customer_order_id' => $order_id],
                ['booking_id' => $booking->get_id()]
            );

            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('payment_schedule'),
                ['deposit_order_id' => $order_id],
                ['booking_id' => $booking->get_id()]
            );
        }

        $order->save();
    }

    /**
     * Handle order completed
     *
     * @param int $order_id Order ID
     */
    public function on_order_completed(int $order_id): void {
        $order = wc_get_order($order_id);
        if (!$order) {
            return;
        }

        $booking_id = $order->get_meta('_wahrb_booking_id');
        if (!$booking_id) {
            return;
        }

        $order_type = $order->get_meta('_wahrb_order_type');
        $booking = new WAHRB_Booking($booking_id);

        if (!$booking->exists()) {
            return;
        }

        global $wpdb;
        $db = WAHRB_Database::instance();

        if ($order_type === 'deposit') {
            $schedule = $booking->get_payment_schedule();
            $update = [
                'deposit_status' => 'paid',
                'deposit_paid_at' => current_time('mysql'),
            ];

            if (
                $schedule
                && !empty($schedule['security_deposit_enabled'])
                && ($schedule['security_mode'] ?? 'capture') === 'capture'
            ) {
                $update['security_status'] = 'captured';
                $update['security_captured_at'] = current_time('mysql');
            }

            // Update deposit status
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('payment_schedule'),
                $update,
                ['booking_id' => $booking_id]
            );

            // Confirm booking
            $booking->confirm();

            // Create balance order if needed
            $schedule = $booking->get_payment_schedule();
            if ($schedule && $schedule['balance_enabled'] && $schedule['balance_amount_final'] > 0) {
                $this->create_balance_order($booking);
            }

        } elseif ($order_type === 'balance') {
            // Update balance status
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('payment_schedule'),
                [
                    'balance_status' => 'paid',
                    'balance_paid_at' => current_time('mysql'),
                ],
                ['booking_id' => $booking_id]
            );

            $booking->mark_balance_paid();
        }
    }

    /**
     * Handle order processing (for COD)
     *
     * @param int $order_id Order ID
     */
    public function on_order_processing(int $order_id): void {
        $order = wc_get_order($order_id);
        if (!$order) {
            return;
        }

        // Only handle COD orders
        if ($order->get_payment_method() !== 'cod') {
            return;
        }

        $booking_id = $order->get_meta('_wahrb_booking_id');
        if (!$booking_id) {
            return;
        }

        $order_type = $order->get_meta('_wahrb_order_type');

        if ($order_type === 'balance') {
            global $wpdb;
            $db = WAHRB_Database::instance();

            // Mark as pending COD
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('payment_schedule'),
                ['balance_payment_method' => 'cod'],
                ['booking_id' => $booking_id]
            );
        }
    }

    /**
     * Customize cart item name
     *
     * @param string $name Item name
     * @param array $cart_item Cart item
     * @param string $cart_item_key Cart item key
     * @return string
     */
    public function cart_item_name(string $name, array $cart_item, string $cart_item_key): string {
        if (!empty($cart_item['wahrb_booking'])) {
            $booking = $cart_item['wahrb_booking'];
            $name .= sprintf(
                '<br><small>%s: %s - %s</small>',
                __('Location', 'wahra-rentals-bookings'),
                date_i18n(get_option('date_format'), strtotime($booking['start_date'])),
                date_i18n(get_option('date_format'), strtotime($booking['end_date']))
            );
        }

        return $name;
    }

    /**
     * Customize order item name
     *
     * @param string $name Item name
     * @param WC_Order_Item $item Order item
     * @param bool $is_visible Is visible
     * @return string
     */
    public function order_item_name(string $name, $item, bool $is_visible): string {
        $start_date = $item->get_meta('_wahrb_start_date');
        $end_date = $item->get_meta('_wahrb_end_date');

        if ($start_date && $end_date) {
            $name .= sprintf(
                '<br><small>%s: %s - %s</small>',
                __('Location', 'wahra-rentals-bookings'),
                date_i18n(get_option('date_format'), strtotime($start_date)),
                date_i18n(get_option('date_format'), strtotime($end_date))
            );
        }

        return $name;
    }

    /**
     * Get payment summary for booking
     *
     * @param int $booking_id Booking ID
     * @return array
     */
    public function get_payment_summary(int $booking_id): array {
        $booking = new WAHRB_Booking($booking_id);
        if (!$booking->exists()) {
            return [];
        }

        $schedule = $booking->get_payment_schedule();
        if (!$schedule) {
            return [];
        }

        $summary = [
            'subtotal' => floatval($schedule['subtotal_amount']),
            'total' => floatval($schedule['total_amount']),
            'currency' => $schedule['currency_code'],
            'deposit' => [
                'enabled' => (bool) $schedule['deposit_enabled'],
                'amount' => floatval($schedule['deposit_amount_final']),
                'status' => $schedule['deposit_status'],
                'paid_at' => $schedule['deposit_paid_at'],
                'refundable' => (bool) $schedule['deposit_refundable'],
            ],
            'security_deposit' => [
                'enabled' => (bool) $schedule['security_deposit_enabled'],
                'amount' => floatval($schedule['security_deposit_amount_final']),
                'mode' => $schedule['security_mode'],
                'status' => $schedule['security_status'],
            ],
            'balance' => [
                'enabled' => (bool) $schedule['balance_enabled'],
                'amount' => floatval($schedule['balance_amount_final']),
                'status' => $schedule['balance_status'],
                'due_at' => $schedule['balance_due_at'],
                'paid_at' => $schedule['balance_paid_at'],
                'allow_cod' => (bool) $schedule['balance_allow_cod'],
            ],
        ];

        return $summary;
    }
}
