<?php

/**
 * Refund Controller
 *
 * REST API endpoints for subscription refunds.
 *
 * @package ArraySubs\Features\Refunds\REST
 * @since 1.0.0
 */

namespace ArraySubs\Features\Refunds\REST;

defined('ABSPATH') || exit;

use ArraySubs\Supports\BaseRestController;
use ArraySubs\Features\Refunds\Services\RefundProcessor;
use ArraySubs\Features\PlanSwitching\Services\ProrationCalculator;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Refund REST controller
 */
class RefundController extends BaseRestController
{
    /**
     * Enable auto-loading
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * REST namespace
     *
     * @var string
     */
    protected $namespace = 'arraysubs/v1';

    /**
     * Constructor
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Register REST routes
     */
    public function registerRoutes(): void
    {
        // Get refund eligibility for a subscription
        register_rest_route($this->namespace, '/subscriptions/(?P<id>\d+)/refund-status', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'getRefundStatus'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'id' => [
                        'description' => __('Subscription ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                ],
            ],
        ]);

        // Get prorated refund preview
        register_rest_route($this->namespace, '/subscriptions/(?P<id>\d+)/prorated-refund-preview', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'getProratedRefundPreview'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'id' => [
                        'description' => __('Subscription ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                ],
            ],
        ]);

        // Issue prorated refund
        register_rest_route($this->namespace, '/subscriptions/(?P<id>\d+)/prorated-refund', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'issueProratedRefund'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'id' => [
                        'description' => __('Subscription ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                    'reason' => [
                        'description' => __('Refund reason', 'arraysubs'),
                        'type' => 'string',
                        'default' => '',
                    ],
                    'cancel_after' => [
                        'description' => __('Cancel subscription after refund', 'arraysubs'),
                        'type' => 'boolean',
                        'default' => true,
                    ],
                ],
            ],
        ]);

        // Issue full refund for an order
        register_rest_route($this->namespace, '/orders/(?P<order_id>\d+)/full-refund', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'issueFullRefund'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'order_id' => [
                        'description' => __('Order ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                    'reason' => [
                        'description' => __('Refund reason', 'arraysubs'),
                        'type' => 'string',
                        'default' => '',
                    ],
                ],
            ],
        ]);

        // Issue partial refund for an order
        register_rest_route($this->namespace, '/orders/(?P<order_id>\d+)/partial-refund', [
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'issuePartialRefund'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'order_id' => [
                        'description' => __('Order ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                    'amount' => [
                        'description' => __('Refund amount', 'arraysubs'),
                        'type' => 'number',
                        'required' => true,
                    ],
                    'reason' => [
                        'description' => __('Refund reason', 'arraysubs'),
                        'type' => 'string',
                        'default' => '',
                    ],
                ],
            ],
        ]);

        // Get refund history for a subscription
        register_rest_route($this->namespace, '/subscriptions/(?P<id>\d+)/refund-history', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'getRefundHistory'],
                'permission_callback' => [$this, 'checkSubscriptionPermission'],
                'args' => [
                    'id' => [
                        'description' => __('Subscription ID', 'arraysubs'),
                        'type' => 'integer',
                        'required' => true,
                    ],
                ],
            ],
        ]);

        // Get refund settings
        register_rest_route($this->namespace, '/settings/refunds', [
            [
                'methods' => WP_REST_Server::READABLE,
                'callback' => [$this, 'getSettings'],
                'permission_callback' => [$this, 'checkAdminPermission'],
            ],
            [
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => [$this, 'saveSettings'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'settings' => [
                        'description' => __('Refund settings', 'arraysubs'),
                        'type' => 'object',
                        'required' => true,
                    ],
                ],
            ],
        ]);
    }

    /**
     * Check admin permission
     *
     * @return bool
     */
    public function checkAdminPermission(): bool
    {
        return current_user_can('manage_woocommerce') || current_user_can('manage_options');
    }

    /**
     * Check subscription permission (admin or owner)
     *
     * @param WP_REST_Request $request Request object
     * @return bool
     */
    public function checkSubscriptionPermission(WP_REST_Request $request): bool
    {
        // Admin can access all
        if (current_user_can('manage_woocommerce') || current_user_can('manage_options')) {
            return true;
        }

        // Customer can view their own subscription refund history
        if (!is_user_logged_in()) {
            return false;
        }

        $subscription_id = absint($request->get_param('id'));
        $subscription = arraysubs_get_subscription($subscription_id);

        if (!$subscription instanceof \WP_Post) {
            return false;
        }

        $customer_id = absint(get_post_meta($subscription_id, '_customer_id', true));

        if ($customer_id <= 0) {
            return false;
        }

        return $customer_id === get_current_user_id();
    }

    /**
     * Get refund status/eligibility for a subscription
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function getRefundStatus(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = absint($request->get_param('id'));

        $subscription = arraysubs_get_subscription($subscription_id);
        if (!$subscription instanceof \WP_Post) {
            return arraysubs_rest_response(
                [],
                404,
                __('Subscription not found', 'arraysubs')
            );
        }

        $refund_status = RefundProcessor::canRefund($subscription_id);

        // Get prorated refund preview
        $proration = ProrationCalculator::calculateProrationRefund($subscription_id);

        $response_data = [
            'subscription_id' => $subscription_id,
            'can_refund' => $refund_status['can_refund'],
            'reason' => $refund_status['reason'],
            'max_refundable_amount' => $refund_status['max_amount'],
            'refundable_order_id' => $refund_status['order_id'] ?? null,
            'total_refunded' => RefundProcessor::getTotalRefunded($subscription_id),
            'formatted_max_amount' => wc_price($refund_status['max_amount']),
            'formatted_total_refunded' => wc_price(RefundProcessor::getTotalRefunded($subscription_id)),
        ];

        // Add prorated refund info if applicable
        if ($proration['success'] && $proration['refund_amount'] > 0) {
            $response_data['prorated_refund'] = [
                'available' => true,
                'amount' => $proration['refund_amount'],
                'days_unused' => $proration['days_unused'],
                'cycle_days' => $proration['cycle_days'],
                'formatted_amount' => $proration['formatted']['refund'],
            ];
        } else {
            $response_data['prorated_refund'] = [
                'available' => false,
                'reason' => $proration['error'] ?? __('No unused days available', 'arraysubs'),
            ];
        }

        return arraysubs_rest_response(
            $response_data,
            200,
            __('Refund status retrieved', 'arraysubs')
        );
    }

    /**
     * Get prorated refund preview
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function getProratedRefundPreview(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = absint($request->get_param('id'));

        $proration = ProrationCalculator::calculateProrationRefund($subscription_id);

        if (!$proration['success']) {
            return arraysubs_rest_response(
                [],
                400,
                $proration['error'] ?? __('Failed to calculate prorated refund', 'arraysubs')
            );
        }

        return arraysubs_rest_response(
            $proration,
            200,
            __('Prorated refund preview calculated', 'arraysubs')
        );
    }

    /**
     * Issue prorated refund
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function issueProratedRefund(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = absint($request->get_param('id'));
        $reason = sanitize_text_field($request->get_param('reason'));
        $cancel_after = (bool) $request->get_param('cancel_after');

        $result = RefundProcessor::processProratedRefund($subscription_id, $reason, $cancel_after);

        if (!$result['success']) {
            return arraysubs_rest_response(
                [],
                400,
                $result['error'] ?? __('Failed to process refund', 'arraysubs')
            );
        }

        return arraysubs_rest_response(
            $result,
            200,
            sprintf(
                /* translators: %s: refund amount */
                __('Prorated refund of %s processed successfully', 'arraysubs'),
                $result['formatted_amount']
            )
        );
    }

    /**
     * Issue full refund for an order
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function issueFullRefund(WP_REST_Request $request): WP_REST_Response
    {
        $order_id = absint($request->get_param('order_id'));
        $reason = sanitize_text_field($request->get_param('reason'));

        // Verify order exists
        $order = wc_get_order($order_id);
        if (!$order) {
            return arraysubs_rest_response(
                [],
                404,
                __('Order not found', 'arraysubs')
            );
        }

        $result = RefundProcessor::processFullRefund($order_id, $reason);

        if (!$result['success']) {
            return arraysubs_rest_response(
                [],
                400,
                $result['error'] ?? __('Failed to process refund', 'arraysubs')
            );
        }

        return arraysubs_rest_response(
            $result,
            200,
            sprintf(
                /* translators: %s: refund amount */
                __('Full refund of %s processed successfully', 'arraysubs'),
                $result['formatted_amount']
            )
        );
    }

    /**
     * Issue partial refund for an order
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function issuePartialRefund(WP_REST_Request $request): WP_REST_Response
    {
        $order_id = absint($request->get_param('order_id'));
        $amount = floatval($request->get_param('amount'));
        $reason = sanitize_text_field($request->get_param('reason'));

        // Verify order exists
        $order = wc_get_order($order_id);
        if (!$order) {
            return arraysubs_rest_response(
                [],
                404,
                __('Order not found', 'arraysubs')
            );
        }

        $result = RefundProcessor::processPartialRefund($order_id, $amount, $reason);

        if (!$result['success']) {
            return arraysubs_rest_response(
                [],
                400,
                $result['error'] ?? __('Failed to process refund', 'arraysubs')
            );
        }

        return arraysubs_rest_response(
            $result,
            200,
            sprintf(
                /* translators: %s: refund amount */
                __('Partial refund of %s processed successfully', 'arraysubs'),
                $result['formatted_amount']
            )
        );
    }

    /**
     * Get refund history for a subscription
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function getRefundHistory(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = absint($request->get_param('id'));

        $subscription = arraysubs_get_subscription($subscription_id);
        if (!$subscription instanceof \WP_Post) {
            return arraysubs_rest_response(
                [],
                404,
                __('Subscription not found', 'arraysubs')
            );
        }

        $history = RefundProcessor::getRefundHistory($subscription_id);

        return arraysubs_rest_response(
            [
                'subscription_id' => $subscription_id,
                'total_refunded' => RefundProcessor::getTotalRefunded($subscription_id),
                'formatted_total_refunded' => wc_price(RefundProcessor::getTotalRefunded($subscription_id)),
                'history' => $history,
            ],
            200,
            __('Refund history retrieved', 'arraysubs')
        );
    }

    /**
     * Get refund settings
     *
     * @return WP_REST_Response
     */
    public function getSettings(): WP_REST_Response
    {
        $settings = [
            'cancellation_behavior' => arraysubs_get_setting('refunds.cancellation_behavior', 'immediate'),
            'auto_gateway_refund' => arraysubs_get_setting('refunds.auto_gateway_refund', true),
            'allow_prorated_refunds' => arraysubs_get_setting('refunds.allow_prorated_refunds', true),
            'minimum_refund_amount' => arraysubs_get_setting('refunds.minimum_amount', 0),
        ];

        return arraysubs_rest_response(
            $settings,
            200,
            __('Refund settings retrieved', 'arraysubs')
        );
    }

    /**
     * Save refund settings
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function saveSettings(WP_REST_Request $request): WP_REST_Response
    {
        $settings = $request->get_param('settings');

        if (!is_array($settings)) {
            return arraysubs_rest_response(
                [],
                400,
                __('Invalid settings format', 'arraysubs')
            );
        }

        // Validate and save settings
        if (isset($settings['cancellation_behavior'])) {
            $allowed_behaviors = ['immediate', 'end_of_period', 'none'];
            $behavior = sanitize_text_field($settings['cancellation_behavior']);
            if (in_array($behavior, $allowed_behaviors, true)) {
                arraysubs_update_setting('refunds.cancellation_behavior', $behavior);
            }
        }

        if (isset($settings['auto_gateway_refund'])) {
            arraysubs_update_setting('refunds.auto_gateway_refund', (bool) $settings['auto_gateway_refund']);
        }

        if (isset($settings['allow_prorated_refunds'])) {
            arraysubs_update_setting('refunds.allow_prorated_refunds', (bool) $settings['allow_prorated_refunds']);
        }

        if (isset($settings['minimum_refund_amount'])) {
            arraysubs_update_setting('refunds.minimum_amount', floatval($settings['minimum_refund_amount']));
        }

        return arraysubs_rest_response(
            ['saved' => true],
            200,
            __('Refund settings saved successfully', 'arraysubs')
        );
    }
}
