<?php

/**
 * Skip Renewal REST Controller
 *
 * REST API endpoints for skip renewal operations.
 *
 * @package ArraySubs\Features\SkipRenewal\REST
 * @since 1.0.0
 */

namespace ArraySubs\Features\SkipRenewal\REST;

defined('ABSPATH') || exit;

use ArraySubs\Supports\BaseRestController;
use ArraySubs\Features\SkipRenewal\Services\SkipManager;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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

    /**
     * Skip manager instance
     *
     * @var SkipManager
     */
    private SkipManager $skip_manager;

    /**
     * Initialize controller
     */
    public function __construct()
    {
        parent::__construct();
        $this->skip_manager = new SkipManager();
    }

    /**
     * Register REST routes
     *
     * @return void
     */
    public function registerRoutes(): void
    {
        // Get skip status
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/skip-status',
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'getSkipStatus'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Can skip check
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/can-skip',
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'canSkip'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Get skip info (combined status and can_skip)
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/skip',
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'getSkipInfo'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Skip cycles
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/skip',
            [
                'methods'             => 'POST',
                'callback'            => [$this, 'skipCycles'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                    'cycles' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'minimum'           => 1,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Undo skip
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/skip',
            [
                'methods'             => 'DELETE',
                'callback'            => [$this, 'undoSkip'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Modify skip
        register_rest_route(
            $this->namespace,
            '/subscriptions/(?P<id>\d+)/skip',
            [
                'methods'             => 'PATCH',
                'callback'            => [$this, 'modifySkip'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                    'cycles' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'minimum'           => 1,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // =========================================
        // Customer-facing routes (My Subscriptions)
        // =========================================

        // Customer: Skip cycles
        register_rest_route(
            $this->namespace,
            '/my-subscriptions/(?P<id>\d+)/skip',
            [
                'methods'             => 'POST',
                'callback'            => [$this, 'skipCycles'],
                'permission_callback' => [$this, 'checkCustomerPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                    'cycles' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'minimum'           => 1,
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );

        // Customer: Undo skip
        register_rest_route(
            $this->namespace,
            '/my-subscriptions/(?P<id>\d+)/undo-skip',
            [
                'methods'             => 'POST',
                'callback'            => [$this, 'undoSkip'],
                'permission_callback' => [$this, 'checkCustomerPermission'],
                'args'                => [
                    'id' => [
                        'required'          => true,
                        'type'              => 'integer',
                        'sanitize_callback' => 'absint',
                    ],
                ],
            ]
        );
    }

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

    /**
     * Check customer permission
     *
     * Validates that the current user is logged in and owns the subscription.
     *
     * @param WP_REST_Request $request Request object.
     * @return bool|WP_Error True if has permission, WP_Error otherwise.
     */
    public function checkCustomerPermission(WP_REST_Request $request)
    {
        if (!is_user_logged_in()) {
            return new WP_Error(
                'not_logged_in',
                __('You must be logged in.', 'arraysubs'),
                ['status' => 401]
            );
        }

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

        if (!$subscription instanceof \WP_Post) {
            return new WP_Error(
                'subscription_not_found',
                __('Subscription not found.', 'arraysubs'),
                ['status' => 404]
            );
        }

        $current_user_id = get_current_user_id();
        $customer_id = (int) get_post_meta($subscription_id, '_customer_id', true);

        if ($customer_id <= 0) {
            return new WP_Error(
                'invalid_subscription_owner',
                __('Invalid subscription ownership data.', 'arraysubs'),
                ['status' => 403]
            );
        }

        if ($current_user_id !== $customer_id) {
            return new WP_Error(
                'permission_denied',
                __('You do not have permission to manage this subscription.', 'arraysubs'),
                ['status' => 403]
            );
        }

        // Check if customer skip is enabled
        $customer_can_skip = arraysubs_get_setting('skip_renewal.customer_can_skip', true);
        if (!$customer_can_skip) {
            return new WP_Error(
                'skip_disabled',
                __('Skip renewal is not available for customers.', 'arraysubs'),
                ['status' => 403]
            );
        }

        return true;
    }

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

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        $status = $this->skip_manager->getSkipStatus($subscription_id);
        $can_skip = $this->skip_manager->canSkip($subscription_id);

        return arraysubs_rest_response([
            'subscription_id' => $subscription_id,
            'skip_status'     => $status,
            'can_skip'        => $can_skip['can_skip'],
            'max_cycles'      => $can_skip['max_cycles'],
            'reason'          => $can_skip['reason'],
        ]);
    }

    /**
     * Check if subscription can skip
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function canSkip(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = $request->get_param('id');

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        $result = $this->skip_manager->canSkip($subscription_id);

        return arraysubs_rest_response([
            'subscription_id' => $subscription_id,
            'can_skip'        => $result['can_skip'],
            'max_cycles'      => $result['max_cycles'],
            'reason'          => $result['reason'],
        ]);
    }

    /**
     * Get combined skip info (status + can_skip + settings)
     *
     * Returns all data needed by the frontend SkipPauseCard.
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function getSkipInfo(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = $request->get_param('id');

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        $status = $this->skip_manager->getSkipStatus($subscription_id);
        $can_skip_result = $this->skip_manager->canSkip($subscription_id);
        $enabled = arraysubs_get_setting('skip_renewal.enabled', false);

        return arraysubs_rest_response([
            'subscription_id'            => $subscription_id,
            'enabled'                    => (bool) $enabled,
            'is_skipping'                => (bool) ($status['is_skipping'] ?? false),
            'skip_remaining'             => (int) ($status['cycles_remaining'] ?? 0),
            'skip_started_date'          => (string) ($status['requested_at'] ?? ''),
            'original_next_payment_date' => (string) ($status['original_date'] ?? ''),
            'skip_reason'                => (string) ($status['reason'] ?? ''),
            'can_skip'                   => (bool) ($can_skip_result['can_skip'] ?? false),
            'max_cycles'                 => (int) ($can_skip_result['max_cycles'] ?? 0),
            'cannot_skip_reason'         => (string) ($can_skip_result['reason'] ?? ''),
        ]);
    }

    /**
     * Skip renewal cycles
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function skipCycles(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = $request->get_param('id');
        $cycles = $request->get_param('cycles');
        $reason = sanitize_textarea_field((string) $request->get_param('reason'));

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        // Check if can skip
        $can_skip = $this->skip_manager->canSkip($subscription_id);
        if (!$can_skip['can_skip']) {
            return arraysubs_rest_response(
                null,
                400,
                $can_skip['reason']
            );
        }

        $user_id = get_current_user_id();
        $result = $this->skip_manager->skip($subscription_id, $cycles, $user_id, $reason);

        if (!$result) {
            return arraysubs_rest_response(
                null,
                500,
                __('Failed to skip renewal cycles.', 'arraysubs')
            );
        }

        // Get updated status
        $status = $this->skip_manager->getSkipStatus($subscription_id);

        return arraysubs_rest_response(
            [
                'subscription_id' => $subscription_id,
                'cycles_skipped'  => $cycles,
                'skip_status'     => $status,
            ],
            200,
            sprintf(
                /* translators: %d: number of cycles skipped */
                __('Successfully skipped %d renewal cycle(s).', 'arraysubs'),
                $cycles
            )
        );
    }

    /**
     * Undo skip for a subscription
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function undoSkip(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = $request->get_param('id');

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        // Check if currently skipping
        $status = $this->skip_manager->getSkipStatus($subscription_id);
        if (!$status['is_skipping']) {
            return arraysubs_rest_response(
                null,
                400,
                __('No skip to undo. Subscription is not currently skipping.', 'arraysubs')
            );
        }

        $user_id = get_current_user_id();
        $result = $this->skip_manager->undoSkip($subscription_id, $user_id);

        if (!$result) {
            return arraysubs_rest_response(
                null,
                500,
                __('Failed to undo skip.', 'arraysubs')
            );
        }

        // Get updated status
        $new_status = $this->skip_manager->getSkipStatus($subscription_id);

        return arraysubs_rest_response(
            [
                'subscription_id' => $subscription_id,
                'skip_status'     => $new_status,
            ],
            200,
            __('Skip cancelled. Original renewal date restored.', 'arraysubs')
        );
    }

    /**
     * Modify skip cycle count
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response
     */
    public function modifySkip(WP_REST_Request $request): WP_REST_Response
    {
        $subscription_id = $request->get_param('id');
        $new_cycles = $request->get_param('cycles');

        $subscription = get_post($subscription_id);
        if (!$subscription instanceof \WP_Post || $subscription->post_type !== 'arraysubs_data') {
            return arraysubs_rest_response(
                null,
                404,
                __('Subscription not found.', 'arraysubs')
            );
        }

        // Check if currently skipping
        $status = $this->skip_manager->getSkipStatus($subscription_id);
        if (!$status['is_skipping']) {
            return arraysubs_rest_response(
                null,
                400,
                __('No skip to modify. Subscription is not currently skipping.', 'arraysubs')
            );
        }

        $user_id = get_current_user_id();
        $result = $this->skip_manager->modifySkip($subscription_id, $new_cycles, $user_id);

        if (!$result) {
            return arraysubs_rest_response(
                null,
                500,
                __('Failed to modify skip.', 'arraysubs')
            );
        }

        // Get updated status
        $new_status = $this->skip_manager->getSkipStatus($subscription_id);

        return arraysubs_rest_response(
            [
                'subscription_id' => $subscription_id,
                'new_cycles'      => $new_cycles,
                'skip_status'     => $new_status,
            ],
            200,
            sprintf(
                /* translators: %d: new number of cycles */
                __('Skip modified to %d cycle(s).', 'arraysubs'),
                $new_cycles
            )
        );
    }
}
