-- =============================================================================
-- 修复订单 Q_176967208700018143d9f6：支付宝已退款成功，但库内未完成
-- =============================================================================
--
-- 【原因简述】
-- 后台发起支付宝退款后，支付宝侧已退款成功，但创建退款记录时因 unique_refund_no
-- 冲突（Duplicate entry 'refund-Q_176967208700018143d9f6'）导致 createRefundRecordAndUpdateOrder
-- 失败，后续流程未执行：订单未置为 refunded、未写退款记录、未扣代理佣金与钱包。
--
-- 【本单实际退款金额】支付宝已退 99.5 元（非整单金额）
--
-- 【与 adminrefundorderlogic 退款链路对照】
-- 代码路径：AdminRefundOrder -> handleAlipayRefund -> createRefundRecordAndUpdateOrder + HandleCommissionAndWalletDeduction
--
--   handleAlipayRefund 成功分支：
--     1) createRefundRecordAndUpdateOrder(order, req, refundNo, refundResp.TradeNo, ...)
--        -> 事务内：Insert order_refund（refund_no, platform_refund_id=TradeNo, order_id, user_id, product_id, refund_amount, status=success, refund_time=NOW()）
--        -> 事务内：Update order（仅 code 中赋了 status=refunded，未显式设 refund_time/version）
--     2) HandleCommissionAndWalletDeduction(ctx, svcCtx, nil, order, req.RefundAmount)
--        -> 该订单下 agent_commission：按 refundAmount 比例冲减，refunded_amount 增加，满额则 status=2（UpdateWithVersion）
--        -> 按代理汇总扣减额，agent_wallet 先扣冻结再扣可用（UpdateWithVersion）
--        -> agent_wallet_transaction 插入 type=refund、金额为负的流水
--
--  本 SQL 对应关系：
--    Step 2  = createRefundRecordAndUpdateOrder 的 Insert order_refund（platform_refund_id 修复时无支付宝 TradeNo 填 NULL，可从支付宝补）
--    Step 3  = createRefundRecordAndUpdateOrder 的 Update order，并显式补全 refund_time、version+1
--    Step 4  = HandleCommissionAndWalletDeduction 对 agent_commission 的冲减（按 99.5 比例）
--    Step 5  = HandleCommissionAndWalletDeduction 对 agent_wallet 扣减 + agent_wallet_transaction 插入
--
-- 【执行前请确认】
-- 1）该订单在支付宝侧已退款成功；2）已备份相关表或先在测试环境执行。
-- Step 2～5 已包在事务中：任一步报错请执行 ROLLBACK；若 step 1 未查到订单（_order_not_found=1）勿执行后续。
-- =============================================================================

-- 与表字段 collation 一致，避免 #1267 Illegal mix of collations（若表为 utf8mb4_general_ci 则改为 COLLATE utf8mb4_general_ci）
SET
    @order_no = CONVERT(
        'Q_176967208700018143d9f6' USING utf8mb4
    ) COLLATE utf8mb4_general_ci;
-- 本单实际退款金额（元）
SET @repair_refund_amount = 99.5;

-- 1) 取订单信息
SELECT
    id,
    user_id,
    product_id,
    amount,
    version INTO @order_id,
    @user_id,
    @product_id,
    @order_amount,
    @order_version
FROM `order`
WHERE
    order_no = @order_no
    AND del_state = 0
LIMIT 1;

SET @refund_amount = @repair_refund_amount;

-- 若无记录则说明订单号错误，终止
SELECT IF(@order_id IS NULL, 1, 0) AS _order_not_found;
-- 若 _order_not_found=1 请勿继续执行后续语句

-- ---------- 以下为事务：任一步报错请执行 ROLLBACK ----------
START TRANSACTION;

-- 2) 补写退款记录（若该订单尚无成功状态的退款记录）
--    代码中 platform_refund_id 来自支付宝 refundResp.TradeNo；修复时无则填 NULL，如有支付宝退款单号可事后 UPDATE 补上
INSERT INTO
    order_refund (
        refund_no,
        order_id,
        user_id,
        product_id,
        platform_refund_id,
        refund_amount,
        refund_reason,
        status,
        del_state,
        version,
        refund_time,
        close_time,
        delete_time
    )
SELECT
    CONCAT(
        'refund-',
        @order_no,
        '-repair'
    ),
    @order_id,
    @user_id,
    @product_id,
    NULL,
    @refund_amount,
    NULL,
    'success',
    0,
    0,
    NOW(),
    NULL,
    NULL
FROM (
        SELECT 1
    ) _one
WHERE
    NOT EXISTS (
        SELECT 1
        FROM order_refund
        WHERE
            order_id = @order_id
            AND status = 'success'
            AND del_state = 0
    );

-- 3) 订单状态改为已退款
UPDATE `order`
SET
    status = 'refunded',
    refund_time = NOW(),
    version = version + 1,
    update_time = NOW()
WHERE
    id = @order_id
    AND del_state = 0
    AND status = 'paid';

-- 4) 代理佣金：按本次退款 99.5 元在该订单的佣金上比例冲减（refunded_amount 增加，满额则 status=2）
SET
    @total_available = (
        SELECT COALESCE(
                SUM(amount - refunded_amount), 0
            )
        FROM agent_commission
        WHERE
            order_id = @order_id
            AND del_state = 0
    );

UPDATE agent_commission
SET
    refunded_amount = LEAST(
        amount,
        refunded_amount + @repair_refund_amount * (amount - refunded_amount) / NULLIF(@total_available, 0)
    ),
    status = CASE
        WHEN LEAST(
            amount,
            refunded_amount + @repair_refund_amount * (amount - refunded_amount) / NULLIF(@total_available, 0)
        ) >= amount THEN 2
        ELSE status
    END,
    version = version + 1,
    update_time = NOW()
WHERE
    order_id = @order_id
    AND del_state = 0
    AND @total_available > 0;

-- 5) 代理钱包扣减 + 流水（仅对尚未存在本单退款流水的代理扣减，避免重复执行导致重复扣款）
DROP TEMPORARY TABLE IF EXISTS _repair_wallet_snapshot;

CREATE TEMPORARY TABLE _repair_wallet_snapshot (
    agent_id BIGINT NOT NULL,
    balance_before DECIMAL(20, 4) NOT NULL,
    frozen_before DECIMAL(20, 4) NOT NULL,
    total_deduct DECIMAL(20, 4) NOT NULL,
    PRIMARY KEY (agent_id)
);

-- 按 99.5 元在该订单各代理间按“可退佣金”比例分配扣减额（与 step 4 一致），仅扣减额>0 的代理
INSERT INTO
    _repair_wallet_snapshot (
        agent_id,
        balance_before,
        frozen_before,
        total_deduct
    )
SELECT
    agent_id,
    balance_before,
    frozen_before,
    total_deduct
FROM (
        SELECT
            c.agent_id, w.balance AS balance_before, w.frozen_balance AS frozen_before, @repair_refund_amount * COALESCE(
                SUM(c.amount - c.refunded_amount), 0
            ) / NULLIF(@total_available, 0) AS total_deduct
        FROM
            agent_commission c
            JOIN agent_wallet w ON w.agent_id = c.agent_id
            AND w.del_state = 0
        WHERE
            c.order_id = @order_id
            AND c.del_state = 0
            AND @total_available > 0
            AND NOT EXISTS (
                SELECT 1
                FROM agent_wallet_transaction t
                WHERE
                    t.agent_id = c.agent_id
                    AND t.transaction_id = @order_no
                    AND t.transaction_type = 'refund'
                    AND t.del_state = 0
            )
        GROUP BY
            c.agent_id, w.balance, w.frozen_balance
    ) _agent_deduct
WHERE
    total_deduct > 0;

-- 从钱包扣减：优先扣冻结余额，不足再扣可用余额
UPDATE agent_wallet w
INNER JOIN _repair_wallet_snapshot r ON w.agent_id = r.agent_id
SET
    w.frozen_balance = w.frozen_balance - LEAST(
        r.total_deduct,
        w.frozen_balance
    ),
    w.balance = w.balance - (
        r.total_deduct - LEAST(
            r.total_deduct,
            w.frozen_balance
        )
    ),
    w.version = w.version + 1,
    w.update_time = NOW()
WHERE
    w.del_state = 0;

-- 插入退款流水（金额为负数）
INSERT INTO
    agent_wallet_transaction (
        delete_time,
        del_state,
        version,
        agent_id,
        transaction_type,
        amount,
        balance_before,
        balance_after,
        frozen_balance_before,
        frozen_balance_after,
        transaction_id,
        related_user_id,
        remark
    )
SELECT
    NULL,
    0,
    0,
    r.agent_id,
    'refund',
    - r.total_deduct,
    r.balance_before,
    r.balance_before - (
        r.total_deduct - LEAST(
            r.total_deduct,
            r.frozen_before
        )
    ),
    r.frozen_before,
    r.frozen_before - LEAST(
        r.total_deduct,
        r.frozen_before
    ),
    @order_no,
    NULL,
    '订单退款修复（支付宝已退，库内补单）'
FROM _repair_wallet_snapshot r;

DROP TEMPORARY TABLE IF EXISTS _repair_wallet_snapshot;

COMMIT;
-- ---------- 事务结束 ----------

-- 6) 校验（可选）
-- 订单应为 refunded
-- SELECT id, order_no, status, refund_time FROM `order` WHERE id = @order_id;
-- 应有 success 退款记录，refund_amount = 99.5
-- SELECT * FROM order_refund WHERE order_id = @order_id AND del_state = 0;
-- 佣金 refunded_amount 按 99.5 比例增加，满额则 status=2
-- SELECT id, agent_id, order_id, amount, refunded_amount, status FROM agent_commission WHERE order_id = @order_id;