<?php

declare(strict_types=1);

namespace HyperfTest\Cases\Platform\Tmall\EntityParse;

use App\Constants\OrderStatus;
use App\Constants\OrderType;
use App\Constants\PaymentMethod;
use App\Constants\RefundType;
use App\Platform\Tmall\EntityParse\Refund;
use PHPUnit\Framework\TestCase;
use ReflectionClass;
use ReflectionMethod;

/**
 * Tmall 闪电退款订单重建 - 数据映射逻辑测试
 *
 * 测试 fixInstantRefundOrders 中的纯数据转换逻辑，
 * 不涉及数据库操作（DB 交互由集成测试覆盖）。
 *
 * @internal
 * @coversNothing
 */
class FixInstantRefundOrdersTest extends TestCase
{
    private Refund $parser;

    /**
     * 样本A attribute: 商品单价 ¥399，退款 ¥177，优惠 ¥22.11
     */
    private string $sampleAttrA = ';fundFlowInfo:CASH^ALIPAY_FUND^支付宝^15489|OTHER_ASSETS^OTHER_ASSETS_GROUP^优惠^2211;bizCode:tmall.hk.refund;disputeRequest:1;leavesCat:50026924;apply_reason_text:不喜欢/不想要;itemBuyAmount:1;seller_batch:true;clj_zero_second_refund:1;DBT:InterceptUnconsignRefund;sku:5085821404607|口味#3B橘子味#3A颜色分类#3B维C 250mg;bgmtc:2026-02-24 13#3B47#3B41;shop_name:TestShop;pmtR:TAPP_USERCOUPON_SP^2211|;tmgSimpleZeroRefund:1;isVirtual:0;EXmrf:17700;warehouseRefund:1;apply_init_refund_fee:17700;mainOrderPostFee:0;itemPrice:39900;toSellerFee:0;';

    /**
     * 样本B attribute: 商品单价 ¥1199，退款 ¥669，优惠 ¥65.89
     */
    private string $sampleAttrB = ';bizCode:tmall.hk.refund;disputeRequest:1;leavesCat:50026872;apply_reason_text:不喜欢/不想要;itemBuyAmount:1;seller_batch:true;clj_zero_second_refund:1;DBT:InterceptUnconsignRefund;sku:5112591851366|颜色分类#3B120粒;bgmtc:2026-02-24 00#3B03#3B54;shop_name:TestShop;pmtR:TAPP_USERCOUPON_SP^6589|;tmgSimpleZeroRefund:1;isVirtual:0;EXmrf:66900;warehouseRefund:1;apply_init_refund_fee:66900;mainOrderPostFee:0;itemPrice:119900;toSellerFee:0;';

    /**
     * 非闪电退款 attribute (无 clj_zero_second_refund)
     */
    private string $sampleAttrNormal = ';bizCode:tmall.hk.refund;itemBuyAmount:2;itemPrice:19900;mainOrderPostFee:1000;sku:123456|颜色#3B红色;pmtR:;';

    protected function setUp(): void
    {
        parent::setUp();

        $reflection = new ReflectionClass(Refund::class);
        $this->parser = $reflection->newInstanceWithoutConstructor();
    }

    // ========================================================
    // 闪电退款检测
    // ========================================================

    /**
     * 验证 parseRefundItemAttribute 正确识别闪电退款标识
     */
    public function testDetectsInstantRefundFromAttribute(): void
    {
        $attrA = $this->parser->parseRefundItemAttribute($this->sampleAttrA);
        $attrB = $this->parser->parseRefundItemAttribute($this->sampleAttrB);

        $this->assertTrue($attrA['clj_zero_second_refund']);
        $this->assertTrue($attrB['clj_zero_second_refund']);
    }

    /**
     * 非闪电退款记录不被识别
     */
    public function testNonInstantRefundNotDetected(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrNormal);

        $this->assertFalse($attr['clj_zero_second_refund']);
    }

    /**
     * 空 attribute 返回空数组
     */
    public function testEmptyAttributeReturnsEmptyArray(): void
    {
        $attr = $this->parser->parseRefundItemAttribute('');

        $this->assertSame([], $attr);
    }

    // ========================================================
    // 金额解析验证
    // ========================================================

    /**
     * 验证 attribute 中的金额字段（单位: 分）正确解析
     */
    public function testAttributeAmountsInFen(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrA);

        // item_price 39900分 = ¥399.00
        $this->assertSame(39900, $attr['item_price']);
        $this->assertSame(1, $attr['item_buy_amount']);

        // 转换为元: 39900 * 1 / 100 = ¥399
        $this->assertEquals(399, $attr['item_price'] * $attr['item_buy_amount'] / 100);
    }

    /**
     * 验证优惠金额聚合（单位: 分 → 元）
     */
    public function testPromotionAmountAggregation(): void
    {
        $attrA = $this->parser->parseRefundItemAttribute($this->sampleAttrA);
        $attrB = $this->parser->parseRefundItemAttribute($this->sampleAttrB);

        // 样本A: 优惠 2211分 = ¥22.11
        $total_discount_a = 0;
        foreach ($attrA['promotions'] as $promo) {
            $total_discount_a += $promo['amount'];
        }
        $this->assertSame(2211, $total_discount_a);
        $this->assertSame(22.11, $total_discount_a / 100);

        // 样本B: 优惠 6589分 = ¥65.89
        $total_discount_b = 0;
        foreach ($attrB['promotions'] as $promo) {
            $total_discount_b += $promo['amount'];
        }
        $this->assertSame(6589, $total_discount_b);
        $this->assertSame(65.89, $total_discount_b / 100);
    }

    // ========================================================
    // 多子项同 tid 金额聚合
    // ========================================================

    /**
     * 同一主订单下多个子订单的金额正确聚合
     */
    public function testMultiSubOrderAmountAggregation(): void
    {
        $attrA = $this->parser->parseRefundItemAttribute($this->sampleAttrA);
        $attrB = $this->parser->parseRefundItemAttribute($this->sampleAttrB);

        // 模拟两条同 tid 记录的 Order 金额聚合
        $total_amount_fen = 0;
        $total_paid_yuan = 0;
        $total_discount_fen = 0;

        // 记录A: item_price=39900, refund_fee=177.00
        $total_amount_fen += $attrA['item_price'] * $attrA['item_buy_amount'];
        $total_paid_yuan += 177.00; // refund_fee in yuan
        foreach ($attrA['promotions'] as $promo) {
            $total_discount_fen += $promo['amount'];
        }

        // 记录B: item_price=119900, refund_fee=669.00
        $total_amount_fen += $attrB['item_price'] * $attrB['item_buy_amount'];
        $total_paid_yuan += 669.00;
        foreach ($attrB['promotions'] as $promo) {
            $total_discount_fen += $promo['amount'];
        }

        // 验证聚合结果
        $this->assertSame(159800, $total_amount_fen);         // 39900 + 119900
        $this->assertEquals(1598, $total_amount_fen / 100);   // ¥1598.00
        $this->assertSame(846.0, $total_paid_yuan);            // ¥177 + ¥669
        $this->assertSame(8800, $total_discount_fen);          // 2211 + 6589
        $this->assertEquals(88, $total_discount_fen / 100);   // ¥88.00
    }

    // ========================================================
    // Order 字段映射验证
    // ========================================================

    /**
     * 验证 bgmtc 时间字段正确解码（#3B → 冒号）
     */
    public function testBgmtcTimeParsing(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrA);

        // bgmtc 原始: 2026-02-24 13#3B47#3B41 → 解码: 2026-02-24 13:47:41
        $this->assertSame('2026-02-24 13:47:41', $attr['bgmtc']);
    }

    /**
     * 验证运费取最大值逻辑
     */
    public function testFreightFeeMaxSelection(): void
    {
        $attrA = $this->parser->parseRefundItemAttribute($this->sampleAttrA);
        $attrB = $this->parser->parseRefundItemAttribute($this->sampleAttrB);

        // 两个样本 mainOrderPostFee 都是 0
        $max_post_fee = max($attrA['main_order_post_fee'], $attrB['main_order_post_fee']);
        $this->assertSame(0, $max_post_fee);
        $this->assertEquals(0, $max_post_fee / 100);
    }

    /**
     * 验证运费正确解析（非零场景）
     */
    public function testFreightFeeNonZero(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrNormal);

        // mainOrderPostFee:1000 = ¥10.00
        $this->assertSame(1000, $attr['main_order_post_fee']);
        $this->assertEquals(10, $attr['main_order_post_fee'] / 100);
    }

    // ========================================================
    // OrderItem 字段映射验证
    // ========================================================

    /**
     * 验证 SKU 正确提取用于产品查询键
     */
    public function testProductKeyFromAttribute(): void
    {
        $attrA = $this->parser->parseRefundItemAttribute($this->sampleAttrA);
        $attrB = $this->parser->parseRefundItemAttribute($this->sampleAttrB);

        // 产品查询键: num_iid:sku_id
        $this->assertSame('5085821404607', $attrA['sku']['sku_id']);
        $this->assertSame('5112591851366', $attrB['sku']['sku_id']);
    }

    /**
     * 验证 quantity 使用 item_buy_amount
     */
    public function testQuantityFromAttribute(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrA);

        $this->assertSame(1, $attr['item_buy_amount']);

        // item_buy_amount > 0 时使用 attribute 值
        $quantity = $attr['item_buy_amount'] > 0 ? $attr['item_buy_amount'] : 1;
        $this->assertSame(1, $quantity);
    }

    /**
     * item_buy_amount = 0 时回退到 record['num']
     */
    public function testQuantityFallbackToNum(): void
    {
        // 当 attribute 中 itemBuyAmount 为 0 或缺失
        $attr = $this->parser->parseRefundItemAttribute(';bizCode:test;itemBuyAmount:0;');

        $record_num = 3;
        $quantity = $attr['item_buy_amount'] > 0 ? $attr['item_buy_amount'] : $record_num;
        $this->assertSame(3, $quantity);
    }

    // ========================================================
    // RefundType 判定验证
    // ========================================================

    /**
     * 闪电退款应返回 INSTANT_REFUND_WITHOUT_RETURN
     */
    public function testInstantRefundTypeOverride(): void
    {
        $attr = $this->parser->parseRefundItemAttribute($this->sampleAttrA);

        $this->assertTrue($attr['clj_zero_second_refund']);
        // 当 clj_zero_second_refund=true 时，refund_type_id 应为 5
        $this->assertSame(5, RefundType::INSTANT_REFUND_WITHOUT_RETURN->value);
    }

    /**
     * 非闪电退款维持原有判定逻辑
     */
    public function testNormalRefundTypePreserved(): void
    {
        // has_good_return=false, good_status=BUYER_NOT_RECEIVED → RETURN_BEFORE_SHIPPING (1)
        $record = ['has_good_return' => false, 'good_status' => 'BUYER_NOT_RECEIVED'];
        $type_id = $this->parser->getRefundTypeId($record);
        $this->assertSame(RefundType::RETURN_BEFORE_SHIPPING->value, $type_id);

        // has_good_return=true → RETURN_AND_REFUND (2)
        $record = ['has_good_return' => true, 'good_status' => ''];
        $type_id = $this->parser->getRefundTypeId($record);
        $this->assertSame(RefundType::RETURN_AND_REFUND->value, $type_id);
    }

    // ========================================================
    // Order 常量值验证
    // ========================================================

    /**
     * 确认重建 Order 使用的常量值
     */
    public function testReconstructedOrderConstants(): void
    {
        $this->assertSame(9, OrderStatus::CANCEL_BEFORE_SHIPPING->value);
        $this->assertSame(9, OrderType::REGRET_ORDER->value);
        $this->assertSame(2, PaymentMethod::ALIPAY_CN->value);
    }

    // ========================================================
    // 边缘情况
    // ========================================================

    /**
     * attribute 无 SKU 信息时 sku 为 null
     */
    public function testMissingSkuInAttribute(): void
    {
        $attr = $this->parser->parseRefundItemAttribute(';clj_zero_second_refund:1;itemPrice:10000;itemBuyAmount:1;');

        $this->assertTrue($attr['clj_zero_second_refund']);
        $this->assertNull($attr['sku']);

        // 无 SKU 时产品查询键的 model_id 应为 null
        $model_id = $attr['sku']['sku_id'] ?? null;
        $this->assertNull($model_id);

        // 查询键格式: item_id:null
        $key = '12345:' . ($model_id ?? 'null');
        $this->assertSame('12345:null', $key);
    }

    /**
     * 无优惠信息时 discount = 0
     */
    public function testNoPromotionsDiscount(): void
    {
        $attr = $this->parser->parseRefundItemAttribute(';clj_zero_second_refund:1;itemPrice:10000;pmtR:;');

        $total_discount = 0;
        foreach ($attr['promotions'] as $promo) {
            $total_discount += $promo['amount'];
        }

        $this->assertSame(0, $total_discount);
    }
}
