-- ============================================================
-- 资金流图谱测试数据
-- 说明：
-- 1. 仅用于开发联调，来源为当前库内 ccdi_bank_statement 与 ccdi_staff_fmy_relation。
-- 2. 不修改 ccdi_bank_statement 原始流水。
-- 3. 只写入资金流图谱必要四表：
--    lx_fund_flow_subject_node
--    lx_fund_flow_account_node
--    lx_fund_flow_own_account_edge
--    lx_fund_flow_detail_edge
-- 4. 测试数据 source_table/source_type/source 标记为 GRAPH_TEST，可重复执行。
-- 5. 默认模拟“全部流水”查询，同时覆盖日期筛选、家庭关系标签和节点穿透。
-- ============================================================

-- 清理上一轮 GRAPH_TEST 测试数据。只清理测试标记数据，不影响 ODPS 基座。
DROP TEMPORARY TABLE IF EXISTS graph_test_old_node_key;
CREATE TEMPORARY TABLE graph_test_old_node_key AS
SELECT object_key
FROM lx_fund_flow_subject_node
WHERE source_type LIKE 'GRAPH_TEST%';

DROP TEMPORARY TABLE IF EXISTS graph_test_old_account_key;
CREATE TEMPORARY TABLE graph_test_old_account_key AS
SELECT object_key
FROM lx_fund_flow_account_node
WHERE source LIKE 'GRAPH_TEST%';

DELETE FROM lx_fund_flow_detail_edge
WHERE source_table = 'GRAPH_TEST';

DELETE FROM lx_fund_flow_own_account_edge
WHERE from_key IN (
        SELECT CONCAT('idno_node/', object_key)
        FROM graph_test_old_node_key
    )
   OR to_key IN (
        SELECT CONCAT('account_node/', object_key)
        FROM graph_test_old_account_key
    );

DELETE FROM lx_fund_flow_account_node
WHERE object_key IN (
    SELECT object_key
    FROM graph_test_old_account_key
);

DELETE FROM lx_fund_flow_subject_node
WHERE object_key IN (
    SELECT object_key
    FROM graph_test_old_node_key
);

-- 选择一个同时具备流水和家庭关系的员工作为中心主体。
DROP TEMPORARY TABLE IF EXISTS graph_seed_subject;
CREATE TEMPORARY TABLE graph_seed_subject AS
SELECT
    bs.cret_no AS person_id,
    COALESCE(NULLIF(MAX(TRIM(staff.name)), ''), NULLIF(MAX(TRIM(bs.LE_ACCOUNT_NAME)), ''), '测试主体') AS person_name,
    COUNT(1) AS trx_cnt
FROM ccdi_bank_statement bs
INNER JOIN ccdi_base_staff staff
    ON staff.id_card = bs.cret_no
INNER JOIN ccdi_staff_fmy_relation r
    ON r.person_id = bs.cret_no
   AND r.status = 1
   AND r.relation_cert_no IS NOT NULL
   AND TRIM(r.relation_cert_no) <> ''
WHERE bs.cret_no IS NOT NULL
  AND TRIM(bs.cret_no) <> ''
  AND bs.LE_ACCOUNT_NO IS NOT NULL
  AND TRIM(bs.LE_ACCOUNT_NO) <> ''
  AND bs.CUSTOMER_ACCOUNT_NAME IS NOT NULL
  AND TRIM(bs.CUSTOMER_ACCOUNT_NAME) NOT IN ('', '0')
  AND (bs.AMOUNT_DR > 0 OR bs.AMOUNT_CR > 0)
  AND TRIM(bs.cret_no) = '617673198109148314'
GROUP BY bs.cret_no
ORDER BY trx_cnt DESC
LIMIT 1;

-- 选 3 个家庭关系人，优先配偶。
DROP TEMPORARY TABLE IF EXISTS graph_seed_counterparty;
CREATE TEMPORARY TABLE graph_seed_counterparty (
    cp_no INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    person_id VARCHAR(100) NOT NULL,
    counterparty_type VARCHAR(32) NOT NULL,
    relation_type VARCHAR(50) NULL,
    counterparty_name VARCHAR(100) NOT NULL,
    counterparty_cert_no VARCHAR(50) NULL,
    counterparty_account_no VARCHAR(128) NOT NULL,
    counterparty_subject_key VARCHAR(64) NOT NULL,
    counterparty_account_key VARCHAR(64) NOT NULL,
    can_expand TINYINT NOT NULL DEFAULT 0
);

INSERT INTO graph_seed_counterparty (
    person_id,
    counterparty_type,
    relation_type,
    counterparty_name,
    counterparty_cert_no,
    counterparty_account_no,
    counterparty_subject_key,
    counterparty_account_key,
    can_expand
)
SELECT
    person_id,
    'FAMILY' AS counterparty_type,
    relation_type,
    relation_name AS counterparty_name,
    relation_cert_no AS counterparty_cert_no,
    CONCAT('FMY_', RIGHT(relation_cert_no, 12)) AS counterparty_account_no,
    MD5(TRIM(relation_cert_no)) AS counterparty_subject_key,
    MD5(CONCAT('FAMILY_ACCOUNT|', TRIM(relation_cert_no), '|', relation_name)) AS counterparty_account_key,
    1 AS can_expand
FROM (
    SELECT
        r.person_id,
        TRIM(r.relation_type) AS relation_type,
        TRIM(r.relation_name) AS relation_name,
        TRIM(r.relation_cert_no) AS relation_cert_no,
        ROW_NUMBER() OVER (
            PARTITION BY r.person_id
            ORDER BY
                CASE WHEN r.relation_type = '配偶' THEN 0 ELSE 1 END,
                r.id
        ) AS rn
    FROM ccdi_staff_fmy_relation r
    INNER JOIN graph_seed_subject s
        ON s.person_id = r.person_id
    WHERE r.status = 1
      AND r.relation_name IS NOT NULL
      AND TRIM(r.relation_name) <> ''
      AND r.relation_cert_no IS NOT NULL
      AND TRIM(r.relation_cert_no) <> ''
) x
WHERE rn <= 3;

-- 再选 6 个普通对手方，模拟资金图里非家庭关系节点。
DROP TEMPORARY TABLE IF EXISTS graph_seed_family_name;
CREATE TEMPORARY TABLE graph_seed_family_name AS
SELECT DISTINCT counterparty_name
FROM graph_seed_counterparty;

INSERT INTO graph_seed_counterparty (
    person_id,
    counterparty_type,
    relation_type,
    counterparty_name,
    counterparty_cert_no,
    counterparty_account_no,
    counterparty_subject_key,
    counterparty_account_key,
    can_expand
)
SELECT
    person_id,
    'NORMAL' AS counterparty_type,
    NULL AS relation_type,
    counterparty_name,
    NULL AS counterparty_cert_no,
    counterparty_account_no,
    MD5(CONCAT('NAME_PROXY|', person_id, '|', counterparty_name)) AS counterparty_subject_key,
    MD5(CONCAT('NAME_ONLY_ACC|', person_id, '|', counterparty_name, '|', counterparty_account_no)) AS counterparty_account_key,
    0 AS can_expand
FROM (
    SELECT
        y.person_id,
        y.counterparty_name,
        COALESCE(y.raw_account_no, CONCAT('NAME_ONLY_', y.rn)) AS counterparty_account_no,
        y.rn
    FROM (
        SELECT
            s.person_id,
            TRIM(bs.CUSTOMER_ACCOUNT_NAME) AS counterparty_name,
            MAX(NULLIF(TRIM(bs.CUSTOMER_ACCOUNT_NO), '')) AS raw_account_no,
            ROW_NUMBER() OVER (
                ORDER BY COUNT(1) DESC, MAX(bs.bank_statement_id)
            ) AS rn
        FROM graph_seed_subject s
        INNER JOIN ccdi_bank_statement bs
            ON bs.cret_no = s.person_id
        LEFT JOIN graph_seed_family_name f
            ON f.counterparty_name = TRIM(bs.CUSTOMER_ACCOUNT_NAME)
        WHERE bs.CUSTOMER_ACCOUNT_NAME IS NOT NULL
          AND TRIM(bs.CUSTOMER_ACCOUNT_NAME) NOT IN ('', '0')
          AND f.counterparty_name IS NULL
          AND (bs.AMOUNT_DR > 0 OR bs.AMOUNT_CR > 0)
        GROUP BY
            s.person_id,
            TRIM(bs.CUSTOMER_ACCOUNT_NAME)
    ) y
) x
WHERE rn <= 6;

-- 取中心员工真实流水作为金额、方向、日期来源，并映射到家庭/普通对手方。
DROP TEMPORARY TABLE IF EXISTS graph_seed_statement;
CREATE TEMPORARY TABLE graph_seed_statement AS
SELECT *
FROM (
    SELECT
        y.*,
        ROW_NUMBER() OVER (
            PARTITION BY y.cp_no
            ORDER BY y.flag, y.trx_date, y.bank_statement_id
        ) AS rn
    FROM (
        SELECT
            x.*,
            ROW_NUMBER() OVER (
                PARTITION BY x.cp_no, x.flag
                ORDER BY x.trx_date, x.bank_statement_id
            ) AS direction_rn
        FROM (
            SELECT
                cp.cp_no,
                bs.bank_statement_id,
                bs.cret_no,
                COALESCE(NULLIF(TRIM(subj.person_name), ''), NULLIF(TRIM(bs.LE_ACCOUNT_NAME), ''), '彭静勇') AS le_account_name,
                TRIM(bs.LE_ACCOUNT_NO) AS le_account_no,
                cp.counterparty_type,
                cp.relation_type,
                cp.counterparty_name AS customer_account_name,
                cp.counterparty_account_no AS customer_account_no,
                cp.counterparty_cert_no,
                cp.counterparty_subject_key,
                cp.counterparty_account_key,
                cp.can_expand,
                bs.TRX_DATE AS trx_date,
                bs.USER_MEMO AS user_memo,
                bs.CASH_TYPE AS cash_type,
                CASE
                    WHEN bs.AMOUNT_DR > 0 THEN bs.AMOUNT_DR
                    WHEN bs.AMOUNT_CR > 0 THEN bs.AMOUNT_CR
                    ELSE 0
                END AS amount,
                CASE
                    WHEN bs.AMOUNT_DR > 0 THEN '1'
                    WHEN bs.AMOUNT_CR > 0 THEN '2'
                    ELSE NULL
                END AS flag,
                bs.AMOUNT_BALANCE AS amount_balance,
                bs.CURRENCY AS currency,
                bs.BANK AS bank,
                bs.BANK_TRX_NUMBER AS bank_trx_number
            FROM graph_seed_counterparty cp
            INNER JOIN graph_seed_subject subj
                ON subj.person_id = cp.person_id
            INNER JOIN ccdi_bank_statement bs
                ON bs.cret_no = cp.person_id
            WHERE bs.cret_no IS NOT NULL
              AND TRIM(bs.cret_no) <> ''
              AND bs.LE_ACCOUNT_NO IS NOT NULL
              AND TRIM(bs.LE_ACCOUNT_NO) <> ''
              AND (bs.AMOUNT_DR > 0 OR bs.AMOUNT_CR > 0)
        ) x
        WHERE x.flag IS NOT NULL
    ) y
    WHERE (y.flag = '1' AND y.direction_rn <= 5)
       OR (y.flag = '2' AND y.direction_rn <= 3)
) x
WHERE x.rn <= 8;

-- 主体点：员工本人。
INSERT IGNORE INTO lx_fund_flow_subject_node (
    object_key,
    idnocfno,
    name,
    cinocsno,
    idno_type,
    staff_id,
    source_type
)
SELECT
    MD5(TRIM(s.person_id)) AS object_key,
    TRIM(s.person_id) AS idnocfno,
    s.person_name AS name,
    NULL AS cinocsno,
    '个人' AS idno_type,
    NULL AS staff_id,
    'GRAPH_TEST_EMPLOYEE' AS source_type
FROM graph_seed_subject s;

-- 主体点：家庭关系人和普通对手方。
INSERT IGNORE INTO lx_fund_flow_subject_node (
    object_key,
    idnocfno,
    name,
    cinocsno,
    idno_type,
    staff_id,
    source_type
)
SELECT DISTINCT
    cp.counterparty_subject_key AS object_key,
    cp.counterparty_cert_no AS idnocfno,
    cp.counterparty_name AS name,
    NULL AS cinocsno,
    CASE WHEN cp.counterparty_cert_no IS NOT NULL THEN '个人' ELSE 'NAME_PROXY' END AS idno_type,
    NULL AS staff_id,
    CASE
        WHEN cp.counterparty_type = 'FAMILY' THEN CONCAT('GRAPH_TEST_FAMILY_', cp.relation_type)
        ELSE 'GRAPH_TEST_COUNTERPARTY'
    END AS source_type
FROM graph_seed_counterparty cp;

-- 账户点：员工真实账户。
INSERT IGNORE INTO lx_fund_flow_account_node (
    object_key,
    acc_no,
    acc_name,
    cinocsno,
    source,
    acc_type,
    acc_idno,
    acc_status,
    acc_date
)
SELECT DISTINCT
    MD5(CONCAT(TRIM(s.le_account_no), TRIM(s.le_account_name))) AS object_key,
    TRIM(s.le_account_no) AS acc_no,
    TRIM(s.le_account_name) AS acc_name,
    NULL AS cinocsno,
    'GRAPH_TEST_BANK_STATEMENT' AS source,
    'INTERNAL' AS acc_type,
    TRIM(s.cret_no) AS acc_idno,
    NULL AS acc_status,
    NULL AS acc_date
FROM graph_seed_statement s;

-- 账户点：对手方账户。
INSERT IGNORE INTO lx_fund_flow_account_node (
    object_key,
    acc_no,
    acc_name,
    cinocsno,
    source,
    acc_type,
    acc_idno,
    acc_status,
    acc_date
)
SELECT DISTINCT
    s.counterparty_account_key AS object_key,
    s.customer_account_no AS acc_no,
    s.customer_account_name AS acc_name,
    NULL AS cinocsno,
    CASE
        WHEN s.counterparty_type = 'FAMILY' THEN 'GRAPH_TEST_FAMILY_RELATION'
        ELSE 'GRAPH_TEST_COUNTERPARTY'
    END AS source,
    'EXTERNAL' AS acc_type,
    s.counterparty_cert_no AS acc_idno,
    NULL AS acc_status,
    NULL AS acc_date
FROM graph_seed_statement s;

-- 持有边：员工主体 -> 员工账户。
INSERT IGNORE INTO lx_fund_flow_own_account_edge (
    object_key,
    from_key,
    to_key,
    acc_name,
    acc_no
)
SELECT DISTINCT
    MD5(CONCAT(MD5(TRIM(s.cret_no)), '|', MD5(CONCAT(TRIM(s.le_account_no), TRIM(s.le_account_name))))) AS object_key,
    CONCAT('idno_node/', MD5(TRIM(s.cret_no))) AS from_key,
    CONCAT('account_node/', MD5(CONCAT(TRIM(s.le_account_no), TRIM(s.le_account_name)))) AS to_key,
    TRIM(s.le_account_name) AS acc_name,
    TRIM(s.le_account_no) AS acc_no
FROM graph_seed_statement s;

-- 持有边：对手方主体 -> 对手方账户。
INSERT IGNORE INTO lx_fund_flow_own_account_edge (
    object_key,
    from_key,
    to_key,
    acc_name,
    acc_no
)
SELECT DISTINCT
    MD5(CONCAT(s.counterparty_subject_key, '|', s.counterparty_account_key)) AS object_key,
    CONCAT('idno_node/', s.counterparty_subject_key) AS from_key,
    CONCAT('account_node/', s.counterparty_account_key) AS to_key,
    s.customer_account_name AS acc_name,
    s.customer_account_no AS acc_no
FROM graph_seed_statement s;

-- 账户层明细边：按流水方向生成 from_key / to_key，并写入家庭关系类型。
INSERT IGNORE INTO lx_fund_flow_detail_edge (
    object_key,
    le_account_name,
    le_account_no,
    customer_account_no,
    customer_account_name,
    trx_date,
    user_memo,
    cash_type,
    amount,
    flag,
    amount_balance,
    currency,
    bank,
    from_key,
    to_key,
    family_relation_type,
    source_table,
    penetrate_level,
    bank_statement_id,
    bank_trx_number
)
SELECT
    MD5(CONCAT('GRAPH_TEST|', s.bank_statement_id, '|', s.counterparty_subject_key, '|', s.rn)) AS object_key,
    s.le_account_name,
    s.le_account_no,
    s.customer_account_no,
    s.customer_account_name,
    SUBSTRING(s.trx_date, 1, 19) AS trx_date,
    s.user_memo,
    s.cash_type,
    s.amount,
    s.flag,
    s.amount_balance,
    s.currency,
    s.bank,
    CASE
        WHEN s.flag = '1'
            THEN CONCAT('account_node/', MD5(CONCAT(TRIM(s.le_account_no), TRIM(s.le_account_name))))
        ELSE CONCAT('account_node/', s.counterparty_account_key)
    END AS from_key,
    CASE
        WHEN s.flag = '1'
            THEN CONCAT('account_node/', s.counterparty_account_key)
        ELSE CONCAT('account_node/', MD5(CONCAT(TRIM(s.le_account_no), TRIM(s.le_account_name))))
    END AS to_key,
    s.relation_type AS family_relation_type,
    'GRAPH_TEST' AS source_table,
    0 AS penetrate_level,
    s.bank_statement_id,
    s.bank_trx_number
FROM graph_seed_statement s
WHERE s.flag IS NOT NULL
  AND s.amount > 0;

-- 一层穿透演示数据：用于验证点击“淘宝”后继续展开到商户节点。
SELECT object_key
INTO @taobao_node
FROM lx_fund_flow_subject_node
WHERE name = ('淘宝' COLLATE utf8mb4_general_ci)
ORDER BY updated_time DESC
LIMIT 1;
SELECT SUBSTRING_INDEX(own.to_key, '/', -1)
INTO @taobao_account_key
FROM lx_fund_flow_own_account_edge own
WHERE own.from_key = (CONCAT('idno_node/', @taobao_node) COLLATE utf8mb4_general_ci)
LIMIT 1;
SET @merchant_a_node := MD5('GRAPH_TEST_MERCHANT_A');
SET @merchant_b_node := MD5('GRAPH_TEST_MERCHANT_B');
SET @merchant_a_acc := MD5('GRAPH_TEST_MERCHANT_A_ACC');
SET @merchant_b_acc := MD5('GRAPH_TEST_MERCHANT_B_ACC');

INSERT INTO lx_fund_flow_subject_node (object_key, idnocfno, name, cinocsno, idno_type, staff_id, source_type)
VALUES
(@merchant_a_node, NULL, '商户A', NULL, 'NAME_PROXY', NULL, 'GRAPH_TEST_TRACE_COUNTERPARTY'),
(@merchant_b_node, NULL, '商户B', NULL, 'NAME_PROXY', NULL, 'GRAPH_TEST_TRACE_COUNTERPARTY')
ON DUPLICATE KEY UPDATE name = VALUES(name), source_type = VALUES(source_type), updated_time = CURRENT_TIMESTAMP;

INSERT INTO lx_fund_flow_account_node (object_key, acc_no, acc_name, source, acc_type)
VALUES
(@merchant_a_acc, 'TRACE-A-001', '商户A', 'GRAPH_TEST', 'EXTERNAL'),
(@merchant_b_acc, 'TRACE-B-001', '商户B', 'GRAPH_TEST', 'EXTERNAL')
ON DUPLICATE KEY UPDATE acc_name = VALUES(acc_name), source = VALUES(source), updated_time = CURRENT_TIMESTAMP;

INSERT INTO lx_fund_flow_own_account_edge (object_key, from_key, to_key, acc_name, acc_no)
VALUES
(MD5(CONCAT(@merchant_a_node, '|', @merchant_a_acc)), CONCAT('idno_node/', @merchant_a_node), CONCAT('account_node/', @merchant_a_acc), '商户A', 'TRACE-A-001'),
(MD5(CONCAT(@merchant_b_node, '|', @merchant_b_acc)), CONCAT('idno_node/', @merchant_b_node), CONCAT('account_node/', @merchant_b_acc), '商户B', 'TRACE-B-001')
ON DUPLICATE KEY UPDATE acc_name = VALUES(acc_name), acc_no = VALUES(acc_no), updated_time = CURRENT_TIMESTAMP;

INSERT INTO lx_fund_flow_detail_edge (
    object_key,
    le_account_name,
    le_account_no,
    customer_account_no,
    customer_account_name,
    trx_date,
    user_memo,
    cash_type,
    amount,
    flag,
    amount_balance,
    currency,
    bank,
    from_key,
    to_key,
    family_relation_type,
    source_table,
    penetrate_level,
    bank_statement_id,
    bank_trx_number
)
VALUES
(MD5('GRAPH_TEST_TAOBAO_TRACE_001'), '淘宝', '淘宝账户', 'TRACE-A-001', '商户A', '2025-03-20 09:18:00', '货款结算', '转账', 12880.00, '1', 0, 'CNY', '测试银行', CONCAT('account_node/', @taobao_account_key), CONCAT('account_node/', @merchant_a_acc), NULL, 'GRAPH_TEST', 1, NULL, 'TRACE001'),
(MD5('GRAPH_TEST_TAOBAO_TRACE_002'), '商户A', 'TRACE-A-001', '淘宝账户', '淘宝', '2025-03-20 16:42:00', '退款冲正', '退款', 3660.50, '2', 0, 'CNY', '测试银行', CONCAT('account_node/', @merchant_a_acc), CONCAT('account_node/', @taobao_account_key), NULL, 'GRAPH_TEST', 1, NULL, 'TRACE002'),
(MD5('GRAPH_TEST_TAOBAO_TRACE_003'), '淘宝', '淘宝账户', 'TRACE-B-001', '商户B', '2025-03-21 11:25:00', '服务费结算', '转账', 8290.30, '1', 0, 'CNY', '测试银行', CONCAT('account_node/', @taobao_account_key), CONCAT('account_node/', @merchant_b_acc), NULL, 'GRAPH_TEST', 1, NULL, 'TRACE003')
ON DUPLICATE KEY UPDATE
    le_account_name = VALUES(le_account_name),
    le_account_no = VALUES(le_account_no),
    customer_account_no = VALUES(customer_account_no),
    customer_account_name = VALUES(customer_account_name),
    trx_date = VALUES(trx_date),
    user_memo = VALUES(user_memo),
    cash_type = VALUES(cash_type),
    amount = VALUES(amount),
    flag = VALUES(flag),
    from_key = VALUES(from_key),
    to_key = VALUES(to_key),
    source_table = VALUES(source_table),
    penetrate_level = VALUES(penetrate_level),
    bank_trx_number = VALUES(bank_trx_number),
    updated_time = CURRENT_TIMESTAMP;

SELECT 'lx_fund_flow_subject_node' AS table_name, COUNT(1) AS graph_test_rows
FROM lx_fund_flow_subject_node
WHERE source_type LIKE 'GRAPH_TEST%'
UNION ALL
SELECT 'lx_fund_flow_account_node' AS table_name, COUNT(1) AS graph_test_rows
FROM lx_fund_flow_account_node
WHERE source LIKE 'GRAPH_TEST%'
UNION ALL
SELECT 'lx_fund_flow_own_account_edge' AS table_name, COUNT(1) AS graph_test_rows
FROM lx_fund_flow_own_account_edge e
WHERE e.from_key IN (
        SELECT CONCAT('idno_node/', object_key)
        FROM lx_fund_flow_subject_node
        WHERE source_type LIKE 'GRAPH_TEST%'
    )
   OR e.to_key IN (
        SELECT CONCAT('account_node/', object_key)
        FROM lx_fund_flow_account_node
        WHERE source LIKE 'GRAPH_TEST%'
    )
UNION ALL
SELECT 'lx_fund_flow_detail_edge' AS table_name, COUNT(1) AS graph_test_rows
FROM lx_fund_flow_detail_edge
WHERE source_table = 'GRAPH_TEST';

SELECT
    s.person_id AS test_person_id,
    s.person_name AS test_person_name,
    MD5(TRIM(s.person_id)) AS test_object_key
FROM graph_seed_subject s;
