<?php

/**
 * Subscription Export Controller
 *
 * REST API endpoints for exporting subscription data.
 *
 * @package ArraySubs\Features\SubscriptionAdmin\REST
 * @since 1.0.0
 */

namespace ArraySubs\Features\SubscriptionAdmin\REST;

defined('ABSPATH') || exit;

use ArraySubs\Supports\BaseRestController;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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

    /**
     * REST base
     *
     * @var string
     */
    protected $rest_base = 'subscriptions/export';

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

    /**
     * Register REST routes
     *
     * @return void
     */
    public function registerRoutes(): void
    {
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base,
            [
                'methods' => 'GET',
                'callback' => [$this, 'exportSubscriptions'],
                'permission_callback' => [$this, 'checkAdminPermission'],
                'args' => [
                    'status' => [
                        'required' => false,
                        'type' => 'string',
                        'default' => 'all',
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                    'format' => [
                        'required' => false,
                        'type' => 'string',
                        'default' => 'csv',
                        'enum' => ['csv', 'json'],
                        'sanitize_callback' => 'sanitize_text_field',
                    ],
                ],
            ]
        );
    }

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

    /**
     * Export subscriptions to CSV or JSON
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error Response
     */
    public function exportSubscriptions(WP_REST_Request $request)
    {
        $status = $request->get_param('status');
        $format = $request->get_param('format');

        // Build query args
        $args = [
            'post_type' => 'arraysubs_data',
            'posts_per_page' => -1, // Export all
            'orderby' => 'date',
            'order' => 'DESC',
        ];

        // Handle status filter
        if ($status && $status !== 'all') {
            $args['post_status'] = $status;
        } else {
            // Include all subscription statuses when "all" is selected
            $args['post_status'] = [
                'arraysubs-active',
                'arraysubs-pending',
                'arraysubs-on-hold',
                'arraysubs-cancelled',
                'arraysubs-expired',
                'arraysubs-trial',
            ];
        }

        $query = new \WP_Query($args);
        $subscriptions = [];

        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                $subscription_id = get_the_ID();
                $subscriptions[] = $this->formatSubscriptionData($subscription_id);
            }
            wp_reset_postdata();
        }

        // Return JSON format
        if ($format === 'json') {
            return new WP_REST_Response($subscriptions, 200);
        }

        // Generate CSV
        $csv = $this->generateCsv($subscriptions);
        $filename = 'subscriptions-export-' . gmdate('Y-m-d-His') . '.csv';

        return $this->createCsvResponse($csv, $filename, count($subscriptions));
    }

    /**
     * Build a raw CSV REST response.
     *
     * WordPress REST responses are JSON-encoded by default, so this endpoint
     * intercepts serving for CSV exports and prints the already-built CSV.
     *
     * @param string $csv      CSV content.
     * @param string $filename Download filename.
     * @param int    $count    Number of exported rows.
     * @return WP_REST_Response Response carrying the CSV download headers.
     */
    private function createCsvResponse(string $csv, string $filename, int $count): WP_REST_Response
    {
        $headers = [
            'Content-Type' => 'text/csv; charset=utf-8',
            'Content-Disposition' => 'attachment; filename="' . sanitize_file_name($filename) . '"',
            'X-Content-Type-Options' => 'nosniff',
            'X-ArraySubs-Export-Count' => (string) $count,
        ];

        add_filter(
            'rest_pre_serve_request',
            static function ($served, $result, $request, $server) use ($csv, $headers) {
                $format = $request instanceof WP_REST_Request
                    ? ($request->get_param('format') ?: 'csv')
                    : 'csv';

                if (
                    ! ($request instanceof WP_REST_Request)
                    || $request->get_route() !== '/arraysubs/v1/subscriptions/export'
                    || $format !== 'csv'
                ) {
                    return $served;
                }

                foreach ($headers as $name => $value) {
                    $server->send_header($name, $value);
                }

                echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

                return true;
            },
            10,
            4
        );

        return new WP_REST_Response(null, 200, $headers);
    }

    /**
     * Format subscription data for export
     *
     * @param int $subscription_id Subscription ID
     * @return array Formatted data
     */
    private function formatSubscriptionData(int $subscription_id): array
    {
        $subscription = get_post($subscription_id);

        // Get customer info
        $customer_id = (int) get_post_meta($subscription_id, '_customer_id', true);
        $customer = $customer_id ? get_userdata($customer_id) : null;
        $customer_name = $customer ? $customer->display_name : '';
        $customer_email = $customer ? $customer->user_email : get_post_meta($subscription_id, '_customer_email', true);

        // Get product info
        $product_name = arraysubs_get_subscription_product_name_by_subscription($subscription_id);

        // Get billing cycle
        $billing_interval = (int) get_post_meta($subscription_id, '_billing_interval', true);
        $billing_period = get_post_meta($subscription_id, '_billing_period', true);
        $billing_cycle = $billing_interval . ' ' . $billing_period;

        // Get status label
        $status_labels = [
            'arraysubs-pending' => __('Pending', 'arraysubs'),
            'arraysubs-active' => __('Active', 'arraysubs'),
            'arraysubs-on-hold' => __('On Hold', 'arraysubs'),
            'arraysubs-cancelled' => __('Cancelled', 'arraysubs'),
            'arraysubs-expired' => __('Expired', 'arraysubs'),
            'arraysubs-trial' => __('Trial', 'arraysubs'),
        ];
        $status = $subscription->post_status;
        $status_label = $status_labels[$status] ?? $status;

        return [
            'id' => $subscription_id,
            'status' => $status_label,
            'customer_name' => $customer_name,
            'customer_email' => $customer_email,
            'product_name' => $product_name,
            'recurring_amount' => (float) get_post_meta($subscription_id, '_recurring_amount', true),
            'currency' => get_post_meta($subscription_id, '_currency', true) ?: 'USD',
            'billing_cycle' => $billing_cycle,
            'start_date' => get_post_meta($subscription_id, '_start_date', true),
            'next_payment_date' => get_post_meta($subscription_id, '_next_payment_date', true),
            'last_payment_date' => get_post_meta($subscription_id, '_last_payment_date', true),
            'end_date' => get_post_meta($subscription_id, '_end_date', true),
            'completed_payments' => (int) get_post_meta($subscription_id, '_completed_payments', true),
            'payment_method' => get_post_meta($subscription_id, '_payment_method_title', true),
            'created_date' => $subscription->post_date,
        ];
    }

    /**
     * Generate CSV string from subscription data
     *
     * @param array $subscriptions Array of subscription data
     * @return string CSV content
     */
    private function generateCsv(array $subscriptions): string
    {
        // Define CSV headers
        $headers = [
            __('Subscription ID', 'arraysubs'),
            __('Status', 'arraysubs'),
            __('Customer Name', 'arraysubs'),
            __('Customer Email', 'arraysubs'),
            __('Product Name', 'arraysubs'),
            __('Recurring Amount', 'arraysubs'),
            __('Currency', 'arraysubs'),
            __('Billing Cycle', 'arraysubs'),
            __('Start Date', 'arraysubs'),
            __('Next Payment Date', 'arraysubs'),
            __('Last Payment Date', 'arraysubs'),
            __('End Date', 'arraysubs'),
            __('Total Payments', 'arraysubs'),
            __('Payment Method', 'arraysubs'),
            __('Created Date', 'arraysubs'),
        ];

        // Build CSV content with BOM for Excel UTF-8 compatibility
        $csv = "\xEF\xBB\xBF";

        // Add headers - escape fields that contain commas or quotes
        $header_row = [];
        foreach ($headers as $header) {
            $header_row[] = $this->escapeCSVField($header);
        }
        $csv .= implode(',', $header_row) . "\n";

        // Add data rows
        foreach ($subscriptions as $sub) {
            $row = [];
            $values = [
                $sub['id'],
                $sub['status'],
                $sub['customer_name'],
                $sub['customer_email'],
                $sub['product_name'],
                $sub['recurring_amount'],
                $sub['currency'],
                $sub['billing_cycle'],
                $sub['start_date'],
                $sub['next_payment_date'],
                $sub['last_payment_date'],
                $sub['end_date'],
                $sub['completed_payments'],
                $sub['payment_method'],
                $sub['created_date'],
            ];

            foreach ($values as $value) {
                $row[] = $this->escapeCSVField((string) $value);
            }

            $csv .= implode(',', $row) . "\n";
        }

        return $csv;
    }

    /**
     * Escape CSV field values to handle commas and quotes
     *
     * @param string $field Field value to escape
     * @return string Escaped field
     */
    private function escapeCSVField(string $field): string
    {
        if (strpos($field, ',') !== false || strpos($field, '"') !== false || strpos($field, "\n") !== false) {
            return '"' . str_replace('"', '""', $field) . '"';
        }
        return $field;
    }
}
