<?php

declare(strict_types=1);

namespace Kylin\Ecommerce\Services;

use Illuminate\Support\Facades\Log;

/**
 * 退款服务
 *
 * 依据《中华人民共和国消费者权益保护法》(2014.3.15)：
 * - 第二十五条：消费者有权自收到商品之日起七日内退货，且无需说明理由
 * - 第五十五条：经营者有欺诈行为的，退一赔三
 *
 * 依据《电子商务法》第二十一条：
 * 押金退还方式、程序需明示
 *
 * 依据《网络交易监督管理办法》：
 * 退款需原路返回
 *
 * 使用方式：
 *   $result = RefundService::checkEligibility($order, now());
 *   $result = RefundService::calculateRefund($order, $refundType);
 */
final class RefundService
{
    /**
     * 退款类型
     */
    public const TYPE_NO_REASON = 'no_reason';       // 7天无理由退货
    public const TYPE_QUALITY_ISSUE = 'quality';     // 质量问题退货
    public const TYPE_WRONG_ITEM = 'wrong_item';     // 发错货
    public const TYPE_NOT_AS_DESCRIBED = 'not_as_described'; // 与描述不符
    public const TYPE_FRAUD = 'fraud';               // 欺诈行为（退一赔三）

    /**
     * 退款状态
     */
    public const STATUS_PENDING = 'pending';
    public const STATUS_APPROVED = 'approved';
    public const STATUS_REFUNDING = 'refunding';
    public const STATUS_REFUNDED = 'refunded';
    public const STATUS_REJECTED = 'rejected';

    /**
     * 不可无理由退货的商品类型
     *
     * 依据《消费者权益保护法》第二十五条：
     * 消费者定作的商品、鲜活易腐商品、在线下载或已拆封的数字化商品、
     * 交付的报纸期刊等不适用无理由退货。
     */
    private const NO_REFUND_CATEGORIES = [
        'customized',      // 定制商品
        'fresh',           // 生鲜易腐
        'digital',         // 数字化商品
        'newspaper',       // 报纸期刊
        'underwear',       // 内衣（拆封后）
        'health_product',  // 保健品（拆封后）
    ];

    /**
     * 检查订单是否可退款
     *
     * @param array $order 订单数据（含 status, created_at, delivered_at, category, is_opened）
     * @param string|null $refundType 退款类型
     * @return array{eligible: bool, reason: string, refund_days_limit: int, law: string}
     */
    public static function checkEligibility(array $order, ?string $refundType = null): array
    {
        $refundDaysLimit = config('kylin-ecommerce.refund_days_limit', 15);

        // 无理由退货：仅在收到商品后 7 天内
        if ($refundType === self::TYPE_NO_REASON || $refundType === null) {
            // 检查是否在 7 天无理由退货期内
            if (!empty($order['delivered_at'])) {
                $daysSinceDelivery = now()->diffInDays($order['delivered_at']);
                if ($daysSinceDelivery > 7) {
                    return [
                        'eligible' => false,
                        'reason' => "已超过 7 天无理由退货期限（已签收 {$daysSinceDelivery} 天）",
                        'refund_days_limit' => 7,
                        'law' => '《消费者权益保护法》第二十五条',
                    ];
                }
            }

            // 检查商品是否属于不可无理由退货类别
            if (!empty($order['category'])) {
                foreach (self::NO_REFUND_CATEGORIES as $category) {
                    if (mb_strpos($order['category'], $category) !== false) {
                        return [
                            'eligible' => false,
                            'reason' => "该商品类别（{$order['category']}）不适用 7 天无理由退货",
                            'refund_days_limit' => 0,
                            'law' => '《消费者权益保护法》第二十五条',
                        ];
                    }
                }
            }

            // 检查商品是否已拆封影响二次销售
            if (!empty($order['is_opened']) && !empty($order['category'])) {
                $noOpenCategories = ['underwear', 'health_product', 'cosmetic'];
                foreach ($noOpenCategories as $cat) {
                    if (mb_strpos($order['category'], $cat) !== false) {
                        return [
                            'eligible' => false,
                            'reason' => '该商品拆封后不支持无理由退货',
                            'refund_days_limit' => 0,
                            'law' => '《消费者权益保护法》第二十五条',
                        ];
                    }
                }
            }
        }

        // 质量问题/发错货/与描述不符：在退款天数限制内
        if (in_array($refundType, [self::TYPE_QUALITY_ISSUE, self::TYPE_WRONG_ITEM, self::TYPE_NOT_AS_DESCRIBED], true)) {
            if (!empty($order['delivered_at'])) {
                $daysSinceDelivery = now()->diffInDays($order['delivered_at']);
                if ($daysSinceDelivery > $refundDaysLimit) {
                    return [
                        'eligible' => false,
                        'reason' => "已超过退款期限（已签收 {$daysSinceDelivery} 天，限制 {$refundDaysLimit} 天）",
                        'refund_days_limit' => $refundDaysLimit,
                        'law' => '《消费者权益保护法》第二十四条',
                    ];
                }
            }
        }

        return [
            'eligible' => true,
            'reason' => '符合退款条件',
            'refund_days_limit' => $refundDaysLimit,
            'law' => '《消费者权益保护法》第二十五条',
        ];
    }

    /**
     * 检查退款资格并记录审计日志
     *
     * @param array $order 订单数据
     * @param string|null $refundType 退款类型
     * @return array
     */
    public static function checkEligibilityWithAudit(array $order, ?string $refundType = null): array
    {
        $result = self::checkEligibility($order, $refundType);

        self::audit('refund_eligibility_checked', [
            'order_id' => $order['id'] ?? null,
            'order_no' => $order['order_no'] ?? null,
            'refund_type' => $refundType,
            'eligible' => $result['eligible'],
            'reason' => $result['reason'],
            'law' => $result['law'] ?? '',
        ]);

        return $result;
    }

    /**
     * 计算退款金额
     *
     * @param array $order 订单数据
     * @param string $refundType 退款类型
     * @return array{refund_amount: float, compensation_amount: float, total: float, law: string}
     */
    public static function calculateRefund(array $order, string $refundType = self::TYPE_NO_REASON): array
    {
        $payAmount = (float) ($order['pay_amount'] ?? 0);
        $totalAmount = (float) ($order['total_amount'] ?? $payAmount);
        $compensationAmount = 0.0;
        $law = '';

        switch ($refundType) {
            case self::TYPE_FRAUD:
                // 退一赔三：退还货款 + 赔偿三倍金额
                $compensationAmount = $totalAmount * 3;
                $law = '《消费者权益保护法》第五十五条：退一赔三';
                break;

            case self::TYPE_QUALITY_ISSUE:
            case self::TYPE_WRONG_ITEM:
            case self::TYPE_NOT_AS_DESCRIBED:
                // 全额退款 + 运费补偿
                $law = '《消费者权益保护法》第二十四条';
                break;

            case self::TYPE_NO_REASON:
            default:
                // 全额退款（消费者承担运费）
                $law = '《消费者权益保护法》第二十五条：7 天无理由退货';
                break;
        }

        return [
            'refund_amount' => round($payAmount, 2),
            'compensation_amount' => round($compensationAmount, 2),
            'total' => round($payAmount + $compensationAmount, 2),
            'original_pay_amount' => $payAmount,
            'refund_type' => $refundType,
            'law' => $law,
        ];
    }

    /**
     * 获取退款方式说明
     *
     * 依据《电子商务法》第二十一条，退款需原路返回。
     *
     * @return array{method: string, description: string, law: string}
     */
    public static function getRefundMethod(): array
    {
        return [
            'method' => '原路返回',
            'description' => '退款将原路返回至用户支付账户，预计 1-7 个工作日到账',
            'law' => '《电子商务法》第二十一条：押金退还方式、程序需明示',
        ];
    }

    /**
     * 生成退款单号
     *
     * @param string $orderNo 原订单号
     * @return string 退款单号
     */
    public static function generateRefundNo(string $orderNo): string
    {
        return 'RF' . date('YmdHis') . str_pad(mt_rand(1, 9999), 4, '0', STR_PAD_LEFT);
    }

    /**
     * 记录退款审计日志
     *
     * 依据《消费者权益保护法》和《电子商务法》，
     * 退款资格检查、金额计算等操作需记录审计日志。
     */
    private static function audit(string $event, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => 'refund',
                'model_id' => $extra['order_id'] ?? 0,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'ecommerce-refund',
            ]);
        } catch (\Throwable $e) {
            Log::warning('退款审计日志写入失败', [
                'error' => $e->getMessage(),
                'event' => $event,
            ]);
        }
    }
}