<?php
/**
 * Payment REST Controller
 *
 * @package WahraRentalsBookings
 */

defined('ABSPATH') || exit;

/**
 * Payment controller class
 */
class WAHRB_Payment_Controller extends WAHRB_REST_Controller {

    /**
     * Route base
     *
     * @var string
     */
    protected $rest_base = 'payments';

    /**
     * Register routes
     */
    public function register_routes(): void {
        // Get payment summary for booking
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<booking_id>\d+)', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_payment_summary'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Mark balance as paid (for COD)
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<booking_id>\d+)/balance-paid', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'mark_balance_paid'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'payment_method' => [
                        'type' => 'string',
                        'default' => 'cod',
                    ],
                    'notes' => [
                        'type' => 'string',
                        'default' => '',
                    ],
                ],
            ],
        ]);

        // Release security deposit
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<booking_id>\d+)/release-security', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'release_security'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Forfeit security deposit
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<booking_id>\d+)/forfeit-security', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'forfeit_security'],
                'permission_callback' => [$this, 'check_vendor_permission'],
                'args' => [
                    'damage_amount' => [
                        'type' => 'number',
                        'required' => true,
                    ],
                    'notes' => [
                        'type' => 'string',
                        'default' => '',
                    ],
                ],
            ],
        ]);

        // Public endpoint: Calculate rental price for a product and date range.
        // Uses __return_true because customers need to see the price breakdown
        // before making a booking decision. This only exposes public pricing data.
        register_rest_route($this->namespace, '/calculate-price', [
            [
                'methods' => WP_REST_Server::READABLE, // GET
                'callback' => [$this, 'calculate_price'],
                'permission_callback' => '__return_true',
                'args' => [
                    'product_id' => [
                        'type' => 'integer',
                        'required' => true,
                    ],
                    'variation_id' => [
                        'type' => 'integer',
                        'default' => 0,
                    ],
                    'start_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'end_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'qty' => [
                        'type' => 'integer',
                        'default' => 1,
                    ],
                ],
            ],
            [
                'methods' => WP_REST_Server::CREATABLE, // POST
                'callback' => [$this, 'calculate_price'],
                'permission_callback' => '__return_true',
                'args' => [
                    'product_id' => [
                        'type' => 'integer',
                        'required' => true,
                    ],
                    'variation_id' => [
                        'type' => 'integer',
                        'default' => 0,
                    ],
                    'start_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'end_date' => [
                        'type' => 'string',
                        'required' => true,
                    ],
                    'qty' => [
                        'type' => 'integer',
                        'default' => 1,
                    ],
                ],
            ],
        ]);

        // Get pending balance orders (vendor)
        register_rest_route($this->namespace, '/vendor/pending-balances', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_pending_balances'],
                'permission_callback' => [$this, 'check_vendor_permission'],
            ],
        ]);

        // Admin: Get all pending payments
        register_rest_route($this->namespace, '/admin/pending-payments', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'get_all_pending_payments'],
                'permission_callback' => [$this, 'check_admin_permission'],
            ],
        ]);
    }

    /**
     * Get payment summary
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_payment_summary($request) {
        $booking_id = absint($request->get_param('booking_id'));
        $vendor_id = $this->get_vendor_id();

        $booking = new WAHRB_Booking($booking_id);

        if (!$booking->exists()) {
            return $this->error('not_found', __('Booking not found.', 'wahra-rentals-bookings'), 404);
        }

        if (!$this->is_admin() && $booking->get('vendor_id') !== $vendor_id) {
            return $this->error('forbidden', __('Access denied.', 'wahra-rentals-bookings'), 403);
        }

        $payment_manager = WAHRB_Payment_Manager::instance();
        $summary = $payment_manager->get_payment_summary($booking_id);

        if (empty($summary)) {
            return $this->error('no_payment', __('No associated payment.', 'wahra-rentals-bookings'));
        }

        // Add order links
        $schedule = $booking->get_payment_schedule();
        if ($schedule) {
            if ($schedule['deposit_order_id']) {
                $summary['deposit']['order_url'] = admin_url('post.php?post=' . $schedule['deposit_order_id'] . '&action=edit');
            }
            if ($schedule['balance_order_id']) {
                $summary['balance']['order_url'] = admin_url('post.php?post=' . $schedule['balance_order_id'] . '&action=edit');
            }
        }

        return $this->success($summary);
    }

    /**
     * Mark balance as paid (COD)
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function mark_balance_paid($request) {
        $booking_id = absint($request->get_param('booking_id'));
        $vendor_id = $this->get_vendor_id();
        $payment_method = sanitize_text_field($request->get_param('payment_method'));
        $notes = sanitize_textarea_field($request->get_param('notes'));

        $booking = new WAHRB_Booking($booking_id);

        if (!$booking->exists()) {
            return $this->error('not_found', __('Booking not found.', 'wahra-rentals-bookings'), 404);
        }

        if (!$this->is_admin() && $booking->get('vendor_id') !== $vendor_id) {
            return $this->error('forbidden', __('Access denied.', 'wahra-rentals-bookings'), 403);
        }

        $schedule = $booking->get_payment_schedule();
        if (!$schedule || !$schedule['balance_enabled']) {
            return $this->error('no_balance', __('No balance for this booking.', 'wahra-rentals-bookings'));
        }

        if ($schedule['balance_status'] === 'paid') {
            return $this->error('already_paid', __('Balance is already paid.', 'wahra-rentals-bookings'));
        }

        // Update balance order if exists
        if ($schedule['balance_order_id']) {
            $order = wc_get_order($schedule['balance_order_id']);
            if ($order) {
                $order->set_payment_method($payment_method);
                $order->set_status('completed', $notes ?: __('Cash payment confirmed by vendor.', 'wahra-rentals-bookings'));
                $order->save();
            }
        }

        // Update payment schedule
        global $wpdb;
        $db = WAHRB_Database::instance();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom table update
        $wpdb->update(
            $db->table('payment_schedule'),
            [
                'balance_status' => 'paid',
                'balance_paid_at' => current_time('mysql'),
                'balance_payment_method' => $payment_method,
            ],
            ['booking_id' => $booking_id]
        );

        // Log
        $db->log('balance_marked_paid', 'booking', $booking_id, [
            'payment_method' => $payment_method,
            'notes' => $notes,
            'by' => $vendor_id,
        ]);

        return $this->success([
            'message' => __('Balance marked as paid.', 'wahra-rentals-bookings'),
        ]);
    }

    /**
     * Release security deposit
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function release_security($request) {
        $booking_id = absint($request->get_param('booking_id'));
        $vendor_id = $this->get_vendor_id();

        $booking = new WAHRB_Booking($booking_id);

        if (!$booking->exists()) {
            return $this->error('not_found', __('Booking not found.', 'wahra-rentals-bookings'), 404);
        }

        if (!$this->is_admin() && $booking->get('vendor_id') !== $vendor_id) {
            return $this->error('forbidden', __('Access denied.', 'wahra-rentals-bookings'), 403);
        }

        $schedule = $booking->get_payment_schedule();
        if (!$schedule || !$schedule['security_deposit_enabled']) {
            return $this->error('no_security', __('No security deposit for this booking.', 'wahra-rentals-bookings'));
        }

        $result = WAHRB_Security_Deposit::release($booking_id);

        if (!$result) {
            return $this->error('release_failed', __('Unable to release security deposit.', 'wahra-rentals-bookings'));
        }

        $message = sprintf(
            /* translators: %s: formatted amount with currency */
            __('Security deposit of %s refunded successfully.', 'wahra-rentals-bookings'),
            wc_price($schedule['security_deposit_amount_final'])
        );

        return $this->success([
            'message' => $message,
        ]);
    }

    /**
     * Forfeit security deposit
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function forfeit_security($request) {
        $booking_id = absint($request->get_param('booking_id'));
        $vendor_id = $this->get_vendor_id();
        $damage_amount = floatval($request->get_param('damage_amount'));
        $notes = sanitize_textarea_field($request->get_param('notes'));

        $booking = new WAHRB_Booking($booking_id);

        if (!$booking->exists()) {
            return $this->error('not_found', __('Booking not found.', 'wahra-rentals-bookings'), 404);
        }

        if (!$this->is_admin() && $booking->get('vendor_id') !== $vendor_id) {
            return $this->error('forbidden', __('Access denied.', 'wahra-rentals-bookings'), 403);
        }

        $schedule = $booking->get_payment_schedule();
        if (!$schedule || !$schedule['security_deposit_enabled']) {
            return $this->error('no_security', __('No security deposit for this booking.', 'wahra-rentals-bookings'));
        }

        $result = WAHRB_Security_Deposit::forfeit($booking_id, $damage_amount, $notes);

        if (!$result) {
            return $this->error('forfeit_failed', __('Unable to forfeit security deposit.', 'wahra-rentals-bookings'));
        }

        $security_amount = floatval($schedule['security_deposit_amount_final']);
        $refund_amount = max(0, $security_amount - $damage_amount);

        $message = $refund_amount > 0
            /* translators: %s: refunded security deposit amount with currency symbol */
            ? sprintf(__('Security deposit partially withheld. %s refunded to client.', 'wahra-rentals-bookings'), wc_price($refund_amount))
            : __('Security deposit fully withheld for damages.', 'wahra-rentals-bookings');

        return $this->success([
            'message' => $message,
            'damage_amount' => $damage_amount,
            'refund_amount' => $refund_amount,
        ]);
    }

    /**
     * Calculate price
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function calculate_price($request) {
        $product_id = absint($request->get_param('product_id'));
        $variation_id = absint($request->get_param('variation_id'));
        $start_date = $this->sanitize_date($request->get_param('start_date'));
        $end_date = $this->sanitize_date($request->get_param('end_date'));
        $qty = absint($request->get_param('qty')) ?: 1;

        if (!$start_date || !$end_date) {
            return $this->error('invalid_dates', __('Dates invalides.', 'wahra-rentals-bookings'));
        }

        $product = wc_get_product($product_id);
        if (!$product) {
            return $this->error('product_not_found', __('Product not found.', 'wahra-rentals-bookings'), 404);
        }

        $engine = WAHRB_Pricing_Engine::instance();
        $calculation = $engine->calculate($product_id, $start_date, $end_date, $variation_id ?: null, $qty);

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

        // Add payment breakdown — per-category settings
        $cat_settings = WAHRB_Platform_Categories::get_product_payment_settings($product_id);
        $deposit_enabled = get_post_meta($product_id, '_wahrb_deposit_enabled', true) === 'yes'
                          || (!empty($cat_settings['deposit_enabled']) && get_post_meta($product_id, '_wahrb_deposit_enabled', true) !== 'no');

        $security_enabled = get_post_meta($product_id, '_wahrb_security_deposit_enabled', true) === 'yes'
                           || (!empty($cat_settings['security_deposit_enabled']) && get_post_meta($product_id, '_wahrb_security_deposit_enabled', true) !== 'no');

        $payment_breakdown = [
            'subtotal' => $calculation['subtotal'],
            'total' => $calculation['total'],
            'currency' => get_woocommerce_currency(),
        ];

        if ($deposit_enabled) {
            $deposit_amount = WAHRB_Deposit_Handler::calculate($calculation['total'], $cat_settings);
            $payment_breakdown['deposit'] = [
                'amount' => $deposit_amount,
                'label' => __('Deposit to pay now', 'wahra-rentals-bookings'),
            ];
            $payment_breakdown['balance'] = [
                'amount' => $calculation['total'] - $deposit_amount,
                'label' => __('Balance to pay before start', 'wahra-rentals-bookings'),
            ];
        }

        if ($security_enabled) {
            $security_amount = WAHRB_Security_Deposit::calculate($product_id, $calculation['total'], $cat_settings);
            $payment_breakdown['security_deposit'] = [
                'amount' => $security_amount,
                'label' => __('Security deposit (refundable)', 'wahra-rentals-bookings'),
            ];
        }

        // Total to pay now (deposit + security)
        $pay_now = ($payment_breakdown['deposit']['amount'] ?? $calculation['total'])
                 + ($payment_breakdown['security_deposit']['amount'] ?? 0);

        $payment_breakdown['pay_now'] = [
            'amount' => $pay_now,
            'label' => __('Total to pay now', 'wahra-rentals-bookings'),
        ];

        return $this->success([
            'calculation' => $calculation,
            'payment' => $payment_breakdown,
        ]);
    }

    /**
     * Get pending balance orders
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_pending_balances($request) {
        $vendor_id = $this->get_vendor_id();

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

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom tables
        $pending = $wpdb->get_results($wpdb->prepare(
            "SELECT
                b.booking_id,
                b.booking_number,
                b.customer_name,
                b.start_dt,
                p.balance_amount_final,
                p.balance_due_at,
                p.balance_order_id
             FROM {$db->table('bookings')} b
             INNER JOIN {$db->table('payment_schedule')} p ON b.booking_id = p.booking_id
             WHERE b.vendor_id = %d
               AND p.balance_enabled = 1
               AND p.balance_status IN ('pending', 'sent')
               AND b.status IN ('confirmed', 'checked_in')
             ORDER BY p.balance_due_at ASC",
            $vendor_id
        ), ARRAY_A);

        $result = [];
        foreach ($pending as $item) {
            $order = $item['balance_order_id'] ? wc_get_order($item['balance_order_id']) : null;

            $result[] = [
                'booking_id' => (int) $item['booking_id'],
                'booking_number' => $item['booking_number'],
                'customer_name' => $item['customer_name'],
                'start_date' => $item['start_dt'],
                'amount' => (float) $item['balance_amount_final'],
                'due_at' => $item['balance_due_at'],
                'order_id' => $item['balance_order_id'] ? (int) $item['balance_order_id'] : null,
                'payment_url' => $order ? $order->get_checkout_payment_url() : null,
                'days_until_due' => $item['balance_due_at']
                    ? (int) ((strtotime($item['balance_due_at']) - time()) / DAY_IN_SECONDS)
                    : null,
            ];
        }

        return $this->success($result);
    }

    /**
     * Get all pending payments (admin)
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_all_pending_payments($request) {
        global $wpdb;
        $db = WAHRB_Database::instance();

        // Pending deposits
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom tables
        $pending_deposits = $wpdb->get_results(
            "SELECT
                b.booking_id,
                b.booking_number,
                b.vendor_id,
                b.customer_name,
                p.deposit_amount_final,
                p.deposit_order_id
             FROM {$db->table('bookings')} b
             INNER JOIN {$db->table('payment_schedule')} p ON b.booking_id = p.booking_id
             WHERE p.deposit_enabled = 1
               AND p.deposit_status = 'pending'
               AND b.status = 'pending'
             ORDER BY b.created_at DESC
             LIMIT 50",
            ARRAY_A
        );

        // Pending balances
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom tables
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $pending_balances = $wpdb->get_results(
            "SELECT
                b.booking_id,
                b.booking_number,
                b.vendor_id,
                b.customer_name,
                b.start_dt,
                p.balance_amount_final,
                p.balance_due_at,
                p.balance_order_id
             FROM {$db->table('bookings')} b
             INNER JOIN {$db->table('payment_schedule')} p ON b.booking_id = p.booking_id
             WHERE p.balance_enabled = 1
               AND p.balance_status IN ('pending', 'sent')
               AND b.status IN ('confirmed', 'checked_in')
             ORDER BY p.balance_due_at ASC
             LIMIT 50",
            ARRAY_A
        );

        // Unreleased security deposits
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom tables
        $unreleased_security = $wpdb->get_results(
            "SELECT
                b.booking_id,
                b.booking_number,
                b.vendor_id,
                b.customer_name,
                b.checked_out_at,
                p.security_deposit_amount_final
             FROM {$db->table('bookings')} b
             INNER JOIN {$db->table('payment_schedule')} p ON b.booking_id = p.booking_id
             WHERE p.security_deposit_enabled = 1
               AND p.security_status = 'captured'
               AND b.status = 'checked_out'
             ORDER BY b.checked_out_at ASC
             LIMIT 50",
            ARRAY_A
        );

        return $this->success([
            'pending_deposits' => $pending_deposits ?: [],
            'pending_balances' => $pending_balances ?: [],
            'unreleased_security' => $unreleased_security ?: [],
            'summary' => [
                'deposits_count' => count($pending_deposits ?: []),
                'balances_count' => count($pending_balances ?: []),
                'security_count' => count($unreleased_security ?: []),
            ],
        ]);
    }
}
