-- 补算「合约跟单盈亏统计表」最近 300 天数据（包含今天）
-- 对应管理后台：合约跟单盈亏统计表 / 补算历史数据
-- 对应后端口径：StatPlatformDailyPnlServiceImpl.computeAndSave(date, includeInternal)
--
-- 性能说明：
--   1. 不按天循环扫描大表，而是先生成 300 天日期维表，再对各业务表按日期一次性 GROUP BY。
--   2. 会重算 stat_platform_daily_pnl 最近 300 天（含执行当天）、include_internal=0/1 两套数据。
--   3. 目标日期范围内先 DELETE 后 INSERT，避免依赖唯一索引。

DROP PROCEDURE IF EXISTS backfill_stat_platform_daily_pnl_300;

DELIMITER //

CREATE PROCEDURE backfill_stat_platform_daily_pnl_300()
BEGIN
    DECLARE v_i INT DEFAULT 299;
    DECLARE v_stat_date DATE;
    DECLARE v_range_start DATETIME;
    DECLARE v_range_end DATETIME;
    DECLARE v_range_start_ms BIGINT;
    DECLARE v_range_end_ms BIGINT;

    SET v_range_start = CAST(DATE_SUB(CURDATE(), INTERVAL 299 DAY) AS DATETIME);
    SET v_range_end = DATE_ADD(CAST(CURDATE() AS DATETIME), INTERVAL 1 DAY);
    SET v_range_start_ms = UNIX_TIMESTAMP(v_range_start) * 1000;
    SET v_range_end_ms = UNIX_TIMESTAMP(v_range_end) * 1000;

    DROP TEMPORARY TABLE IF EXISTS tmp_stat_dates;
    CREATE TEMPORARY TABLE tmp_stat_dates (
        stat_date DATE NOT NULL PRIMARY KEY
    ) ENGINE=MEMORY;

    WHILE v_i >= 0 DO
        SET v_stat_date = DATE_SUB(CURDATE(), INTERVAL v_i DAY);
        INSERT INTO tmp_stat_dates (stat_date) VALUES (v_stat_date);
        SET v_i = v_i - 1;
    END WHILE;

    DELETE p
    FROM stat_platform_daily_pnl p
    JOIN tmp_stat_dates d ON d.stat_date = p.stat_date
    WHERE p.include_internal IN (0, 1);

    INSERT INTO stat_platform_daily_pnl (
        stat_date,
        include_internal,
        deposit_amount,
        withdraw_amount,
        self_open_count,
        self_open_amount,
        self_close_profit,
        self_close_loss,
        self_close_diff,
        self_fee,
        self_funding_fee,
        copy_open_count,
        copy_open_amount,
        copy_close_profit,
        copy_close_loss,
        copy_close_diff,
        copy_fee,
        copy_funding_fee,
        updated_time
    )
    SELECT
        d.stat_date,
        ii.include_internal,
        COALESCE(dep.deposit_amount, 0) AS deposit_amount,
        COALESCE(wd.withdraw_amount, 0) AS withdraw_amount,
        COALESCE(ord.self_open_count, 0) AS self_open_count,
        COALESCE(ord.self_open_amount, 0) AS self_open_amount,
        COALESCE(ord.self_close_profit, 0) AS self_close_profit,
        COALESCE(ord.self_close_loss, 0) AS self_close_loss,
        COALESCE(ord.self_close_loss, 0) - COALESCE(ord.self_close_profit, 0) AS self_close_diff,
        CASE
            WHEN COALESCE(tx.gross_self_fee, 0) + COALESCE(tx.gross_copy_fee, 0) = 0 THEN 0
            ELSE ROUND(
                COALESCE(tx.gross_self_fee, 0)
                - (COALESCE(rw.total_rebates, 0) * COALESCE(tx.gross_self_fee, 0)
                   / (COALESCE(tx.gross_self_fee, 0) + COALESCE(tx.gross_copy_fee, 0))),
                8
            )
        END AS self_fee,
        COALESCE(tx.self_funding_fee, 0) AS self_funding_fee,
        COALESCE(ord.copy_open_count, 0) AS copy_open_count,
        COALESCE(ord.copy_open_amount, 0) AS copy_open_amount,
        COALESCE(ord.copy_close_profit, 0) AS copy_close_profit,
        COALESCE(ord.copy_close_loss, 0) AS copy_close_loss,
        COALESCE(ord.copy_close_loss, 0) - COALESCE(ord.copy_close_profit, 0) AS copy_close_diff,
        CASE
            WHEN COALESCE(tx.gross_self_fee, 0) + COALESCE(tx.gross_copy_fee, 0) = 0 THEN 0
            ELSE ROUND(
                COALESCE(tx.gross_copy_fee, 0)
                - (COALESCE(rw.total_rebates, 0)
                   - (COALESCE(rw.total_rebates, 0) * COALESCE(tx.gross_self_fee, 0)
                      / (COALESCE(tx.gross_self_fee, 0) + COALESCE(tx.gross_copy_fee, 0)))),
                8
            )
        END AS copy_fee,
        COALESCE(tx.copy_funding_fee, 0) AS copy_funding_fee,
        NOW() AS updated_time
    FROM tmp_stat_dates d
    CROSS JOIN (
        SELECT 0 AS include_internal
        UNION ALL
        SELECT 1 AS include_internal
    ) ii
    LEFT JOIN (
        SELECT
            DATE(md.create_time) AS stat_date,
            ii.include_internal,
            COALESCE(SUM(md.amount), 0) AS deposit_amount
        FROM member_deposit md
        CROSS JOIN (
            SELECT 0 AS include_internal
            UNION ALL
            SELECT 1 AS include_internal
        ) ii
        LEFT JOIN member m ON m.id = md.member_id
        WHERE md.create_time >= v_range_start
          AND md.create_time < v_range_end
          AND md.unit LIKE '%USDT%'
          AND (
              ii.include_internal = 1
              OR (md.member_id IS NOT NULL AND (m.id IS NULL OR COALESCE(m.is_internal, 0) <> 1))
          )
        GROUP BY DATE(md.create_time), ii.include_internal
    ) dep ON dep.stat_date = d.stat_date AND dep.include_internal = ii.include_internal
    LEFT JOIN (
        SELECT
            DATE(wr.deal_time) AS stat_date,
            ii.include_internal,
            COALESCE(SUM(wr.total_amount), 0) AS withdraw_amount
        FROM withdraw_record wr
        CROSS JOIN (
            SELECT 0 AS include_internal
            UNION ALL
            SELECT 1 AS include_internal
        ) ii
        LEFT JOIN member m ON m.id = wr.member_id
        WHERE wr.status = 3
          AND wr.deal_time >= v_range_start
          AND wr.deal_time < v_range_end
          AND wr.coin_id LIKE '%USDT%'
          AND (
              ii.include_internal = 1
              OR (wr.member_id IS NOT NULL AND (m.id IS NULL OR COALESCE(m.is_internal, 0) <> 1))
          )
        GROUP BY DATE(wr.deal_time), ii.include_internal
    ) wd ON wd.stat_date = d.stat_date AND wd.include_internal = ii.include_internal
    LEFT JOIN (
        SELECT
            DATE(FROM_UNIXTIME(coe.deal_time / 1000)) AS stat_date,
            ii.include_internal,
            SUM(CASE WHEN coe.entrust_type = 0 AND coe.follow_id IS NULL THEN 1 ELSE 0 END) AS self_open_count,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 0 AND coe.follow_id IS NULL
                              THEN coe.traded_volume * coe.traded_price ELSE 0 END), 0) AS self_open_amount,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 1 AND coe.follow_id IS NULL AND coe.profit_and_loss > 0
                              THEN coe.profit_and_loss ELSE 0 END), 0) AS self_close_profit,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 1 AND coe.follow_id IS NULL AND coe.profit_and_loss < 0
                              THEN -coe.profit_and_loss ELSE 0 END), 0) AS self_close_loss,
            SUM(CASE WHEN coe.entrust_type = 0 AND coe.follow_id IS NOT NULL THEN 1 ELSE 0 END) AS copy_open_count,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 0 AND coe.follow_id IS NOT NULL
                              THEN coe.traded_volume * coe.traded_price ELSE 0 END), 0) AS copy_open_amount,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 1 AND coe.follow_id IS NOT NULL AND coe.profit_and_loss > 0
                              THEN coe.profit_and_loss ELSE 0 END), 0) AS copy_close_profit,
            COALESCE(SUM(CASE WHEN coe.entrust_type = 1 AND coe.follow_id IS NOT NULL AND coe.profit_and_loss < 0
                              THEN -coe.profit_and_loss ELSE 0 END), 0) AS copy_close_loss
        FROM contract_order_entrust coe
        CROSS JOIN (
            SELECT 0 AS include_internal
            UNION ALL
            SELECT 1 AS include_internal
        ) ii
        LEFT JOIN member m ON m.id = coe.member_id
        WHERE coe.status = 3
          AND coe.experience_record_id IS NULL
          AND coe.entrust_type IN (0, 1)
          AND coe.deal_time >= v_range_start_ms
          AND coe.deal_time < v_range_end_ms
          AND (
              ii.include_internal = 1
              OR (coe.member_id IS NOT NULL AND (m.id IS NULL OR COALESCE(m.is_internal, 0) <> 1))
          )
        GROUP BY DATE(FROM_UNIXTIME(coe.deal_time / 1000)), ii.include_internal
    ) ord ON ord.stat_date = d.stat_date AND ord.include_internal = ii.include_internal
    LEFT JOIN (
        SELECT
            DATE(mt.create_time) AS stat_date,
            ii.include_internal,
            COALESCE(SUM(CASE WHEN mt.type = 19 THEN -mt.amount ELSE 0 END), 0) AS gross_self_fee,
            COALESCE(SUM(CASE WHEN mt.type = 37 THEN -mt.amount ELSE 0 END), 0) AS gross_copy_fee,
            COALESCE(SUM(CASE WHEN mt.type = 26 THEN -mt.amount ELSE 0 END), 0) AS self_funding_fee,
            COALESCE(SUM(CASE WHEN mt.type = 42 THEN -mt.amount ELSE 0 END), 0) AS copy_funding_fee
        FROM member_transaction mt
        CROSS JOIN (
            SELECT 0 AS include_internal
            UNION ALL
            SELECT 1 AS include_internal
        ) ii
        LEFT JOIN member m ON m.id = mt.member_id
        WHERE mt.type IN (19, 37, 26, 42)
          AND mt.create_time >= v_range_start
          AND mt.create_time < v_range_end
          AND (
              ii.include_internal = 1
              OR (mt.member_id IS NOT NULL AND (m.id IS NULL OR COALESCE(m.is_internal, 0) <> 1))
          )
        GROUP BY DATE(mt.create_time), ii.include_internal
    ) tx ON tx.stat_date = d.stat_date AND tx.include_internal = ii.include_internal
    LEFT JOIN (
        SELECT
            DATE(crr.create_time) AS stat_date,
            ii.include_internal,
            COALESCE(SUM(crr.num), 0) AS total_rebates
        FROM contract_reward_record crr
        CROSS JOIN (
            SELECT 0 AS include_internal
            UNION ALL
            SELECT 1 AS include_internal
        ) ii
        LEFT JOIN member m ON m.id = crr.from_member_id
        WHERE crr.type IN (0, 1, 2)
          AND crr.create_time >= v_range_start
          AND crr.create_time < v_range_end
          AND (
              ii.include_internal = 1
              OR (crr.from_member_id IS NOT NULL AND (m.id IS NULL OR COALESCE(m.is_internal, 0) <> 1))
          )
        GROUP BY DATE(crr.create_time), ii.include_internal
    ) rw ON rw.stat_date = d.stat_date AND rw.include_internal = ii.include_internal
    ORDER BY d.stat_date, ii.include_internal;

    DROP TEMPORARY TABLE IF EXISTS tmp_stat_dates;
END//

DELIMITER ;

CALL backfill_stat_platform_daily_pnl_300();

DROP PROCEDURE IF EXISTS backfill_stat_platform_daily_pnl_300;
