<?php

declare(strict_types=1);

namespace Instinctor\Services;

use Instinctor\Core\Config;
use Instinctor\Core\DB;
use Instinctor\Core\Auth;
use Instinctor\Core\Mailer;


if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * RMA Service
 * Manages product returns and refund requests
 */
class RMAService
{
    private static array $statuses = [
        'pending' => 'Pending Review',
        'approved' => 'Approved',
        'rejected' => 'Rejected',
        'shipped' => 'Return Shipped',
        'received' => 'Received',
        'refunded' => 'Refunded',
        'completed' => 'Completed',
    ];

    private static array $reasons = [
        'defective' => 'Defective or Damaged',
        'wrong_item' => 'Wrong Item Received',
        'not_as_described' => 'Not as Described',
        'changed_mind' => 'Changed My Mind',
        'other' => 'Other',
    ];

    private static array $refundTypes = [
        'original' => 'Original Payment Method',
        'store_credit' => 'Store Credit',
        'exchange' => 'Exchange for Different Item',
    ];

    /**
     * Generate RMA number
     */
    public static function generateRMANumber(): string
    {
        $prefix = 'RMA';
        // phpcs:disable WordPress.DateTime.RestrictedFunctions -- date() used intentionally for local-timezone formatting; gmdate() would force UTC and change behavior.
        $number = $prefix . date('Ymd') . strtoupper(wp_generate_password(6, false, false));
        // phpcs:enable WordPress.DateTime.RestrictedFunctions
        
        $table = DB::prefix() . 'instinctor_rma';
        
        while (DB::get_var(DB::prepare("SELECT id FROM $table WHERE rma_number = %s", $number))) {
            // phpcs:disable WordPress.DateTime.RestrictedFunctions -- date() used intentionally for local-timezone formatting; gmdate() would force UTC and change behavior.
            $number = $prefix . date('Ymd') . strtoupper(wp_generate_password(6, false, false));
            // phpcs:enable WordPress.DateTime.RestrictedFunctions
        }
        
        return $number;
    }

    /**
     * Create return request
     */
    public static function createRequest(array $data): ?object
    {
        $rma_table = DB::prefix() . 'instinctor_rma';
        $items_table = DB::prefix() . 'instinctor_rma_items';

        // Validate order exists and belongs to customer
        $orders_table = DB::prefix() . 'instinctor_orders';
        $order = DB::get_row(DB::prepare(
            "SELECT * FROM $orders_table WHERE id = %d AND customer_id = %d",
            intval($data['order_id']),
            intval($data['customer_id'])
        ));

        if (!$order) {
            return null;
        }

        // Check return window (default 30 days)
        $returnDays = intval(Config::get('instinctor_return_days', 30));
        $orderDate = strtotime($order->created_at);
        if (time() - $orderDate > $returnDays * 86400) {
            return null; // Past return window
        }

        $rmaNumber = self::generateRMANumber();

        DB::insert($rma_table, [
            'rma_number' => $rmaNumber,
            'order_id' => intval($data['order_id']),
            'customer_id' => intval($data['customer_id']),
            'reason' => sanitize_text_field($data['reason']),
            'reason_detail' => sanitize_textarea_field($data['reason_detail'] ?? ''),
            'refund_type' => sanitize_text_field($data['refund_type'] ?? 'original'),
            'status' => 'pending',
        ]);

        $rmaId = DB::insert_id();

        // Add items
        if (!empty($data['items']) && is_array($data['items'])) {
            foreach ($data['items'] as $item) {
                DB::insert($items_table, [
                    'rma_id' => $rmaId,
                    'order_item_id' => intval($item['order_item_id']),
                    'product_id' => intval($item['product_id']),
                    'quantity' => intval($item['quantity']),
                ]);
            }
        }

        // Send notification email
        self::sendStatusEmail($rmaId, 'created');

        return self::getById($rmaId);
    }

    /**
     * Get RMA by ID
     */
    public static function getById(int $id): ?object
    {
        $p = DB::prefix();
        $rma_table = DB::prefix() . 'instinctor_rma';
        $items_table = DB::prefix() . 'instinctor_rma_items';

        $rma = DB::get_row(DB::prepare("SELECT * FROM $rma_table WHERE id = %d", $id));
        
        if ($rma) {
            $rma->items = DB::get_results(DB::prepare(
                "SELECT ri.*, p.name as product_name
                 FROM $items_table ri
                 JOIN {$p}instinctor_products p ON ri.product_id = p.id
                 WHERE ri.rma_id = %d",
                $id
            ));
            $rma->status_label = self::$statuses[$rma->status] ?? $rma->status;
            $rma->reason_label = self::$reasons[$rma->reason] ?? $rma->reason;
        }

        return $rma;
    }

    /**
     * Get RMA by number
     */
    public static function getByNumber(string $number): ?object
    {
        $table = DB::prefix() . 'instinctor_rma';

        $id = DB::get_var(DB::prepare("SELECT id FROM $table WHERE rma_number = %s", $number));
        
        return $id ? self::getById((int) $id) : null;
    }

    /**
     * Get customer's RMAs
     */
    public static function getCustomerRMAs(int $customerId): array
    {
        $table = DB::prefix() . 'instinctor_rma';

        $rmas = DB::get_results(DB::prepare(
            "SELECT * FROM $table WHERE customer_id = %d ORDER BY created_at DESC",
            $customerId
        ));

        foreach ($rmas as &$rma) {
            $rma->status_label = self::$statuses[$rma->status] ?? $rma->status;
        }

        return $rmas;
    }

    /**
     * Get all RMAs (admin)
     */
    public static function getAll(array $args = []): array
    {
        $table = DB::prefix() . 'instinctor_rma';

        $where = '1=1';
        $params = [];

        if (!empty($args['status'])) {
            $where .= ' AND status = %s';
            $params[] = $args['status'];
        }

        if (!empty($args['search'])) {
            $where .= ' AND (rma_number LIKE %s)';
            $params[] = '%' . DB::esc_like($args['search']) . '%';
        }

        $orderBy = 'created_at DESC';
        if (!empty($args['orderby'])) {
            $orderBy = sanitize_sql_orderby($args['orderby'] . ' ' . ($args['order'] ?? 'DESC')) ?: $orderBy;
        }

        $limit = intval($args['limit'] ?? 50);
        $offset = intval($args['offset'] ?? 0);

        $sql = "SELECT * FROM $table WHERE $where ORDER BY $orderBy LIMIT %d OFFSET %d";
        $params[] = $limit;
        $params[] = $offset;

        // phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- Query uses $wpdb->prepare, orderBy is sanitized with sanitize_sql_orderby
        $rmas = DB::get_results(DB::prepare($sql, ...$params));

        foreach ($rmas as &$rma) {
            $rma->status_label = self::$statuses[$rma->status] ?? $rma->status;
            $rma->reason_label = self::$reasons[$rma->reason] ?? $rma->reason;
        }

        return $rmas;
    }

    /**
     * Update RMA status
     */
    public static function updateStatus(int $id, string $status, ?int $processedBy = null, ?string $notes = null): bool
    {
        $table = DB::prefix() . 'instinctor_rma';

        $update = ['status' => $status];
        
        if ($processedBy) {
            $update['processed_by'] = $processedBy;
        }
        
        if ($notes) {
            $rma = self::getById($id);
            $update['admin_notes'] = $rma->admin_notes ? $rma->admin_notes . "\n\n" . $notes : $notes;
        }

        $result = DB::update($table, $update, ['id' => $id]);

        if ($result !== false) {
            self::sendStatusEmail($id, $status);
        }

        return $result !== false;
    }

    /**
     * Approve RMA
     */
    public static function approve(int $id, float $refundAmount, float $restockingFee = 0, ?string $notes = null): bool
    {
        $table = DB::prefix() . 'instinctor_rma';

        DB::update($table, [
            'status' => 'approved',
            'refund_amount' => $refundAmount,
            'restocking_fee' => $restockingFee,
            'admin_notes' => $notes,
            'processed_by' => Auth::userId(),
        ], ['id' => $id]);

        self::sendStatusEmail($id, 'approved');

        return true;
    }

    /**
     * Reject RMA
     */
    public static function reject(int $id, string $reason): bool
    {
        return self::updateStatus($id, 'rejected', Auth::userId(), $reason);
    }

    /**
     * Add tracking number
     */
    public static function addTracking(int $id, string $trackingNumber): bool
    {
        $table = DB::prefix() . 'instinctor_rma';

        return DB::update($table, [
            'tracking_number' => sanitize_text_field($trackingNumber),
            'status' => 'shipped',
        ], ['id' => $id]) !== false;
    }

    /**
     * Mark as received
     */
    public static function markReceived(int $id, array $itemConditions = []): bool
    {
        $items_table = DB::prefix() . 'instinctor_rma_items';

        // Update item conditions
        foreach ($itemConditions as $itemId => $condition) {
            DB::update($items_table, [
                'condition_received' => sanitize_text_field($condition),
            ], ['id' => $itemId]);
        }

        return self::updateStatus($id, 'received', Auth::userId());
    }

    /**
     * Process refund
     */
    public static function processRefund(int $id): bool
    {
        $rma = self::getById($id);
        
        if (!$rma || !in_array($rma->status, ['received', 'approved'])) {
            return false;
        }

        // Restock items if needed
        foreach ($rma->items as $item) {
            if ($item->restock) {
                self::restockItem($item->product_id, $item->quantity);
            }
        }

        if ($rma->refund_type === 'store_credit') {
            // Create gift card as store credit
            GiftCardService::create([
                'amount' => $rma->refund_amount,
                'recipient_email' => self::getCustomerEmail($rma->customer_id),
                'message' => 'Store credit from return ' . $rma->rma_number,
            ]);
        } elseif ($rma->refund_type === 'original') {
            // Create refund record
            RefundService::createRefund([
                'order_id' => $rma->order_id,
                'amount' => $rma->refund_amount,
                'reason' => 'RMA: ' . $rma->rma_number,
                'restore_stock' => false, // Already handled above
            ]);
        }

        return self::updateStatus($id, 'refunded', Auth::userId());
    }

    /**
     * Complete RMA
     */
    public static function complete(int $id): bool
    {
        return self::updateStatus($id, 'completed', Auth::userId());
    }

    /**
     * Restock item
     */
    private static function restockItem(int $productId, int $quantity): void
    {
        $table = DB::prefix() . 'instinctor_products';

        DB::query(DB::prepare(
            "UPDATE $table SET stock_quantity = stock_quantity + %d WHERE id = %d",
            $quantity, $productId
        ));
    }

    /**
     * Get customer email
     */
    private static function getCustomerEmail(int $customerId): string
    {
        $table = DB::prefix() . 'instinctor_customers';

        return DB::get_var(DB::prepare("SELECT email FROM $table WHERE id = %d", $customerId)) ?? '';
    }

    /**
     * Send status email
     */
    private static function sendStatusEmail(int $rmaId, string $status): void
    {
        $p = DB::prefix();
        $rma = self::getById($rmaId);
        if (!$rma) return;

        $email = self::getCustomerEmail($rma->customer_id);
        if (!$email) return;

        // Get customer name
        $customer = DB::get_row(DB::prepare(
            "SELECT * FROM {$p}instinctor_customers WHERE id = %d",
            $rma->customer_id
        ));
        $customerName = $customer ? trim($customer->first_name . ' ' . $customer->last_name) : 'Customer';

        // Get order number
        $order = DB::get_row(DB::prepare(
            "SELECT * FROM {$p}instinctor_orders WHERE id = %d",
            $rma->order_id
        ));
        $orderNumber = $order->order_number ?? $rma->order_id;

        // Map status to EmailService template
        $templateMap = [
            'approved'  => 'rma_approved',
            'received'  => 'rma_received',
            'completed' => 'rma_completed',
        ];

        $refundTypeLabels = [
            'original' => 'refund to your original payment method',
            'store_credit' => 'store credit',
            'exchange' => 'exchange',
        ];

        $templateData = [
            'customer_name' => $customerName,
            'rma_number' => $rma->rma_number,
            'order_number' => $orderNumber,
            'refund_type' => $refundTypeLabels[$rma->refund_type] ?? 'refund',
            'refund_amount' => CurrencyService::formatPrice($rma->refund_amount ?? 0),
        ];

        // Use EmailService for mapped templates
        if (isset($templateMap[$status])) {
            EmailService::send($templateMap[$status], $email, $templateData);
        } else {
            // Fallback for other statuses - use direct email
            $subjects = [
                'created' => 'Return Request Received - ' . $rma->rma_number,
                'rejected' => 'Return Request Update - ' . $rma->rma_number,
                'refunded' => 'Refund Processed - ' . $rma->rma_number,
            ];

            $subject = $subjects[$status] ?? 'Return Update - ' . $rma->rma_number;
            $message = self::getEmailTemplate($rma, $status);

            Mailer::html($email, $subject, $message);
        }
    }

    /**
     * Get email template (fallback for statuses not in EmailService)
     */
    private static function getEmailTemplate(object $rma, string $status): string
    {
        $siteName = Config::get('instinctor_store_name', get_bloginfo('name'));
        
        $statusMessages = [
            'created' => 'We have received your return request and will review it shortly.',
            'rejected' => 'Unfortunately, your return request could not be approved.',
            'refunded' => 'Your refund has been processed and should appear in your account within 5-10 business days.',
        ];

        $message = $statusMessages[$status] ?? 'Your return request has been updated.';

        ob_start();
        ?>
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
        <body style="margin:0; padding:0; background:#f5f5f7; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
            <table width="100%" cellpadding="0" cellspacing="0" style="background:#f5f5f7; padding:40px 20px;">
                <tr>
                    <td align="center">
                        <table width="600" cellpadding="0" cellspacing="0" style="background:#fff; border-radius:8px; overflow:hidden;">
                            <tr>
                                <td style="padding:32px 40px; background:#1d1d1f; color:#fff;">
                                    <h1 style="margin:0; font-size:24px; font-weight:600;">Return Request Update</h1>
                                </td>
                            </tr>
                            <tr>
                                <td style="padding:32px 40px; font-size:15px; line-height:1.6; color:#1d1d1f;">
                                    <p style="margin:0 0 20px;"><?php echo esc_html($message); ?></p>
                                    
                                    <div style="background:#f5f5f7; padding:20px; border-radius:8px; margin:20px 0;">
                                        <p style="margin:0 0 8px;"><strong>RMA Number:</strong> <?php echo esc_html($rma->rma_number); ?></p>
                                        <p style="margin:0 0 8px;"><strong>Status:</strong> <?php echo esc_html(ucfirst($status)); ?></p>
                                        <?php if ($rma->refund_amount): ?>
                                        <p style="margin:0;"><strong>Refund Amount:</strong> <?php echo esc_html(CurrencyService::formatPrice($rma->refund_amount)); ?></p>
                                        <?php endif; ?>
                                    </div>

                                    <?php if ($rma->admin_notes && in_array($status, ['rejected'])): ?>
                                    <p style="margin:20px 0 0;"><strong>Notes:</strong> <?php echo esc_html($rma->admin_notes); ?></p>
                                    <?php endif; ?>
                                </td>
                            </tr>
                            <tr>
                                <td style="padding:24px 40px; background:#f5f5f7; text-align:center; font-size:13px; color:#86868b;">
                                    <a href="<?php echo esc_url(home_url()); ?>" style="color:#1d1d1f; text-decoration:none; font-weight:500;"><?php echo esc_html($siteName); ?></a>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </body>
        </html>
        <?php
        return ob_get_clean();
    }

    /**
     * Get status options
     */
    public static function getStatuses(): array
    {
        return self::$statuses;
    }

    /**
     * Get reason options
     */
    public static function getReasons(): array
    {
        return self::$reasons;
    }

    /**
     * Get refund type options
     */
    public static function getRefundTypes(): array
    {
        return self::$refundTypes;
    }

    /**
     * Get pending RMA count
     */
    public static function getPendingCount(): int
    {
        $table = DB::prefix() . 'instinctor_rma';

        // Check if table exists
        $tableExists = DB::get_var("SHOW TABLES LIKE '$table'") === $table;
        if (!$tableExists) {
            return 0;
        }

        return (int) DB::get_var("SELECT COUNT(*) FROM $table WHERE status = 'pending'");
    }
}
