<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.ccdi.project.mapper.CcdiFundGraphMapper">

    <resultMap id="FundGraphNodeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO">
        <id property="objectKey" column="objectKey"/>
        <result property="nodeKey" column="nodeKey"/>
        <result property="nodeName" column="nodeName"/>
        <result property="idNo" column="idNo"/>
        <result property="cinocsno" column="cinocsno"/>
        <result property="idnoType" column="idnoType"/>
        <result property="staffId" column="staffId"/>
        <result property="sourceType" column="sourceType"/>
        <result property="nodeType" column="nodeType"/>
        <result property="identityType" column="identityType"/>
        <result property="relationType" column="relationType"/>
        <result property="accountCount" column="accountCount"/>
        <result property="createdTime" column="createdTime"/>
        <result property="updatedTime" column="updatedTime"/>
        <result property="canExpand" column="canExpand"/>
        <result property="depth" column="depth"/>
        <result property="totalAmount" column="totalAmount"/>
        <result property="transactionCount" column="transactionCount"/>
    </resultMap>

    <resultMap id="FundGraphEdgeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO">
        <id property="edgeKey" column="edgeKey"/>
        <result property="fromKey" column="fromKey"/>
        <result property="toKey" column="toKey"/>
        <result property="fromObjectKey" column="fromObjectKey"/>
        <result property="toObjectKey" column="toObjectKey"/>
        <result property="fromName" column="fromName"/>
        <result property="toName" column="toName"/>
        <result property="totalAmount" column="totalAmount"/>
        <result property="transactionCount" column="transactionCount"/>
        <result property="firstTrxDate" column="firstTrxDate"/>
        <result property="lastTrxDate" column="lastTrxDate"/>
        <result property="direction" column="direction"/>
        <result property="familyRelationType" column="familyRelationType"/>
        <result property="sourceType" column="sourceType"/>
        <result property="relationDesc" column="relationDesc"/>
        <result property="sourceDesc" column="sourceDesc"/>
        <result property="remark" column="remark"/>
        <result property="depth" column="depth"/>
        <result property="canTrace" column="canTrace"/>
    </resultMap>

    <resultMap id="FundGraphStatementResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO">
        <id property="bankStatementId" column="bankStatementId"/>
        <result property="trxDate" column="trxDate"/>
        <result property="leAccountNo" column="leAccountNo"/>
        <result property="leAccountName" column="leAccountName"/>
        <result property="customerAccountName" column="customerAccountName"/>
        <result property="customerAccountNo" column="customerAccountNo"/>
        <result property="cashType" column="cashType"/>
        <result property="userMemo" column="userMemo"/>
        <result property="amount" column="amount"/>
        <result property="direction" column="direction"/>
        <result property="familyRelationType" column="familyRelationType"/>
    </resultMap>

    <sql id="detailFilter">
        <if test="query.transactionStartTime != null and query.transactionStartTime != ''">
            AND d.trx_date <![CDATA[ >= ]]> (#{query.transactionStartTime} COLLATE utf8mb4_general_ci)
        </if>
        <if test="query.transactionEndTime != null and query.transactionEndTime != ''">
            AND d.trx_date <![CDATA[ <= ]]>
            (CASE
                WHEN LENGTH(TRIM(#{query.transactionEndTime})) = 10
                    THEN CONCAT(TRIM(#{query.transactionEndTime}), ' 23:59:59')
                ELSE TRIM(#{query.transactionEndTime})
            END COLLATE utf8mb4_general_ci)
        </if>
        <if test="query.amountMin != null">
            AND d.amount <![CDATA[ >= ]]> #{query.amountMin}
        </if>
        <if test="query.amountMax != null">
            AND d.amount <![CDATA[ <= ]]> #{query.amountMax}
        </if>
        <if test="query.direction != null and query.direction != ''">
            AND d.flag = (#{query.direction} COLLATE utf8mb4_general_ci)
        </if>
    </sql>

    <sql id="subjectJoinRows">
        SELECT
            d.object_key AS detailObjectKey,
            d.bank_statement_id AS bankStatementId,
            d.trx_date AS trxDate,
            d.le_account_no AS leAccountNo,
            d.le_account_name AS leAccountName,
            d.customer_account_name AS customerAccountName,
            d.customer_account_no AS customerAccountNo,
            d.cash_type AS cashType,
            d.user_memo AS userMemo,
            d.amount,
            d.flag AS direction,
            d.family_relation_type AS familyRelationType,
            from_subject.object_key AS fromObjectKey,
            to_subject.object_key AS toObjectKey,
            CONCAT('idno_node/', from_subject.object_key) AS fromKey,
            CONCAT('idno_node/', to_subject.object_key) AS toKey,
            from_subject.name AS fromName,
            to_subject.name AS toName,
            from_subject.idnocfno AS fromIdNo,
            to_subject.idnocfno AS toIdNo
        FROM lx_fund_flow_detail_edge d
        INNER JOIN lx_fund_flow_own_account_edge from_own
            ON from_own.to_key = d.from_key
        INNER JOIN lx_fund_flow_subject_node from_subject
            ON CONCAT('idno_node/', from_subject.object_key) = from_own.from_key
        INNER JOIN lx_fund_flow_own_account_edge to_own
            ON to_own.to_key = d.to_key
        INNER JOIN lx_fund_flow_subject_node to_subject
            ON CONCAT('idno_node/', to_subject.object_key) = to_own.from_key
        WHERE 1 = 1
        <include refid="detailFilter"/>
    </sql>

    <sql id="subjectJoinRowsByCenter">
        SELECT
            d.object_key AS detailObjectKey,
            d.bank_statement_id AS bankStatementId,
            d.trx_date AS trxDate,
            d.le_account_no AS leAccountNo,
            d.le_account_name AS leAccountName,
            d.customer_account_name AS customerAccountName,
            d.customer_account_no AS customerAccountNo,
            d.cash_type AS cashType,
            d.user_memo AS userMemo,
            d.amount,
            d.flag AS direction,
            d.family_relation_type AS familyRelationType,
            center_subject.object_key AS fromObjectKey,
            to_subject.object_key AS toObjectKey,
            CONCAT('idno_node/', center_subject.object_key) AS fromKey,
            CONCAT('idno_node/', to_subject.object_key) AS toKey,
            center_subject.name AS fromName,
            to_subject.name AS toName,
            center_subject.idnocfno AS fromIdNo,
            to_subject.idnocfno AS toIdNo
        FROM lx_fund_flow_subject_node center_subject
        INNER JOIN lx_fund_flow_own_account_edge from_own
            ON from_own.from_key = CONCAT('idno_node/', center_subject.object_key)
        INNER JOIN lx_fund_flow_detail_edge d
            ON d.from_key = from_own.to_key
        INNER JOIN lx_fund_flow_own_account_edge to_own
            ON to_own.to_key = d.to_key
        INNER JOIN lx_fund_flow_subject_node to_subject
            ON to_subject.object_key = SUBSTRING(to_own.from_key, 11)
        WHERE center_subject.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
        <include refid="detailFilter"/>
        UNION ALL
        SELECT
            d.object_key AS detailObjectKey,
            d.bank_statement_id AS bankStatementId,
            d.trx_date AS trxDate,
            d.le_account_no AS leAccountNo,
            d.le_account_name AS leAccountName,
            d.customer_account_name AS customerAccountName,
            d.customer_account_no AS customerAccountNo,
            d.cash_type AS cashType,
            d.user_memo AS userMemo,
            d.amount,
            d.flag AS direction,
            d.family_relation_type AS familyRelationType,
            from_subject.object_key AS fromObjectKey,
            center_subject.object_key AS toObjectKey,
            CONCAT('idno_node/', from_subject.object_key) AS fromKey,
            CONCAT('idno_node/', center_subject.object_key) AS toKey,
            from_subject.name AS fromName,
            center_subject.name AS toName,
            from_subject.idnocfno AS fromIdNo,
            center_subject.idnocfno AS toIdNo
        FROM lx_fund_flow_subject_node center_subject
        INNER JOIN lx_fund_flow_own_account_edge to_own
            ON to_own.from_key = CONCAT('idno_node/', center_subject.object_key)
        INNER JOIN lx_fund_flow_detail_edge d
            ON d.to_key = to_own.to_key
        INNER JOIN lx_fund_flow_own_account_edge from_own
            ON from_own.to_key = d.from_key
        INNER JOIN lx_fund_flow_subject_node from_subject
            ON from_subject.object_key = SUBSTRING(from_own.from_key, 11)
        WHERE center_subject.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
          AND from_subject.object_key != center_subject.object_key
        <include refid="detailFilter"/>
    </sql>

    <sql id="fundGraphSubjectColumns">
            n.object_key AS objectKey,
            CONCAT('idno_node/', n.object_key) AS nodeKey,
            n.name AS nodeName,
            n.idnocfno AS idNo,
            n.cinocsno AS cinocsno,
            n.idno_type AS idnoType,
            n.staff_id AS staffId,
            n.source_type AS sourceType,
            CASE
                WHEN n.idno_type = 'NAME_PROXY' OR n.source_type LIKE '%COUNTERPARTY%' THEN 'PROXY'
                ELSE 'PERSON'
            END AS nodeType,
            CASE
                WHEN n.idnocfno IS NOT NULL AND TRIM(n.idnocfno) != '' THEN 'IDNO'
                ELSE 'NAME'
            END AS identityType,
            CASE
                WHEN n.source_type LIKE 'GRAPH_TEST_FAMILY_%' THEN REPLACE(n.source_type, 'GRAPH_TEST_FAMILY_', '')
                ELSE NULL
            END AS relationType,
            CASE
                WHEN EXISTS (
                    SELECT 1
                    FROM lx_fund_flow_own_account_edge own
                    WHERE own.from_key = CONCAT('idno_node/', n.object_key)
                ) THEN 1
                ELSE 0
            END AS canExpand,
            (
                SELECT COUNT(1)
                FROM lx_fund_flow_own_account_edge own_count
                WHERE own_count.from_key = CONCAT('idno_node/', n.object_key)
            ) AS accountCount,
            DATE_FORMAT(n.created_time, '%Y-%m-%d %H:%i:%s') AS createdTime,
            DATE_FORMAT(n.updated_time, '%Y-%m-%d %H:%i:%s') AS updatedTime,
            0 AS depth,
            0 AS totalAmount,
            0 AS transactionCount
    </sql>

    <select id="selectFundGraphSubjects" resultMap="FundGraphNodeResultMap">
        SELECT
            <include refid="fundGraphSubjectColumns"/>
        FROM lx_fund_flow_subject_node n
        WHERE n.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
    </select>

    <select id="selectFundGraphSubjectsByExactKeyword" resultMap="FundGraphNodeResultMap">
        SELECT exact_rows.*
        FROM (
            SELECT
                <include refid="fundGraphSubjectColumns"/>,
                0 AS matchOrder
            FROM lx_fund_flow_subject_node n
            WHERE n.idnocfno = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
            UNION ALL
            SELECT
                <include refid="fundGraphSubjectColumns"/>,
                1 AS matchOrder
            FROM lx_fund_flow_subject_node n
            WHERE n.object_key = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
              AND (
                n.idnocfno IS NULL
                OR n.idnocfno != (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
              )
        ) exact_rows
        ORDER BY exact_rows.matchOrder, exact_rows.nodeName
        LIMIT
        <choose>
            <when test="query.limit != null and query.limit > 0">
                #{query.limit}
            </when>
            <otherwise>
                20
            </otherwise>
        </choose>
    </select>

    <select id="selectFundGraphSubjectsByName" resultMap="FundGraphNodeResultMap">
        SELECT
            <include refid="fundGraphSubjectColumns"/>
        FROM lx_fund_flow_subject_node n
        WHERE n.name LIKE (CONCAT('%', TRIM(#{query.keyword}), '%') COLLATE utf8mb4_general_ci)
        ORDER BY
            CASE
                WHEN n.staff_id IS NOT NULL AND TRIM(n.staff_id) != '' THEN 0
                WHEN UPPER(IFNULL(n.source_type, '')) LIKE '%EMPLOYEE%' THEN 0
                WHEN n.source_type LIKE '%员工%' THEN 0
                ELSE 1
            END,
            n.name
        LIMIT
        <choose>
            <when test="query.limit != null and query.limit > 0">
                #{query.limit}
            </when>
            <otherwise>
                20
            </otherwise>
        </choose>
    </select>

    <select id="selectFundGraphEdges" resultMap="FundGraphEdgeResultMap">
        SELECT
            MD5(CONCAT(graph_rows.fromKey, '|', graph_rows.toKey, '|', graph_rows.direction, '|', IFNULL(graph_rows.familyRelationType, ''))) AS edgeKey,
            graph_rows.fromKey,
            graph_rows.toKey,
            graph_rows.fromObjectKey,
            graph_rows.toObjectKey,
            MAX(graph_rows.fromName) AS fromName,
            MAX(graph_rows.toName) AS toName,
            SUM(graph_rows.amount) AS totalAmount,
            COUNT(1) AS transactionCount,
            MIN(graph_rows.trxDate) AS firstTrxDate,
            MAX(graph_rows.trxDate) AS lastTrxDate,
            graph_rows.direction,
            graph_rows.familyRelationType,
            'BANK' AS sourceType,
            NULL AS relationDesc,
            NULL AS sourceDesc,
            NULL AS remark,
            1 AS depth,
            CASE
                WHEN MAX(
                    CASE
                        WHEN graph_rows.fromObjectKey = #{query.objectKey} THEN
                            CASE
                                WHEN graph_rows.toIdNo IS NOT NULL AND TRIM(graph_rows.toIdNo) != '' THEN 1
                                ELSE 0
                            END
                        ELSE
                            CASE
                                WHEN graph_rows.fromIdNo IS NOT NULL AND TRIM(graph_rows.fromIdNo) != '' THEN 1
                                ELSE 0
                            END
                    END
                ) = 1 THEN 1
                WHEN EXISTS (
                    SELECT 1
                    FROM lx_fund_flow_own_account_edge own
                    WHERE own.from_key = CASE
                        WHEN graph_rows.fromObjectKey = #{query.objectKey}
                            THEN graph_rows.toKey
                        ELSE graph_rows.fromKey
                    END
                ) THEN 1
                ELSE 0
            END AS canTrace
        FROM (
            <include refid="subjectJoinRowsByCenter"/>
        ) graph_rows
        WHERE 1 = 1
        GROUP BY
            graph_rows.fromKey,
            graph_rows.toKey,
            graph_rows.fromObjectKey,
            graph_rows.toObjectKey,
            graph_rows.direction,
            graph_rows.familyRelationType
        <if test="query.minTotalAmount != null">
            HAVING SUM(graph_rows.amount) <![CDATA[ >= ]]> #{query.minTotalAmount}
        </if>
        ORDER BY totalAmount DESC, transactionCount DESC
        LIMIT #{query.limit}
    </select>

    <select id="selectFundGraphManualEdges" resultMap="FundGraphEdgeResultMap">
        SELECT
            m.object_key AS edgeKey,
            CONCAT('idno_node/', m.from_object_key) AS fromKey,
            CONCAT('idno_node/', m.to_object_key) AS toKey,
            m.from_object_key AS fromObjectKey,
            m.to_object_key AS toObjectKey,
            COALESCE(from_subject.name, m.from_name) AS fromName,
            COALESCE(to_subject.name, m.to_name) AS toName,
            m.amount AS totalAmount,
            m.transaction_count AS transactionCount,
            DATE_FORMAT(m.created_time, '%Y-%m-%d %H:%i:%s') AS firstTrxDate,
            DATE_FORMAT(m.created_time, '%Y-%m-%d %H:%i:%s') AS lastTrxDate,
            m.direction,
            NULL AS familyRelationType,
            m.source_type AS sourceType,
            m.relation_desc AS relationDesc,
            m.source_desc AS sourceDesc,
            m.remark,
            1 AS depth,
            0 AS canTrace
        FROM lx_fund_flow_manual_edge m
        LEFT JOIN lx_fund_flow_subject_node from_subject
            ON from_subject.object_key = m.from_object_key
        LEFT JOIN lx_fund_flow_subject_node to_subject
            ON to_subject.object_key = m.to_object_key
        WHERE m.source_type = 'MANUAL'
          AND (
            m.from_object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
            OR m.to_object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
          )
        ORDER BY m.updated_time DESC
        LIMIT #{query.limit}
    </select>

    <select id="selectFundGraphEdgeDetails" resultMap="FundGraphStatementResultMap">
        SELECT
            graph_rows.bankStatementId,
            graph_rows.trxDate,
            graph_rows.leAccountNo,
            graph_rows.leAccountName,
            graph_rows.customerAccountName,
            graph_rows.customerAccountNo,
            graph_rows.cashType,
            graph_rows.userMemo,
            graph_rows.amount,
            graph_rows.direction,
            graph_rows.familyRelationType
        FROM (
            <include refid="subjectJoinRows"/>
        ) graph_rows
        WHERE graph_rows.fromKey = (#{query.fromKey} COLLATE utf8mb4_general_ci)
          AND graph_rows.toKey = (#{query.toKey} COLLATE utf8mb4_general_ci)
        <if test="query.direction != null and query.direction != ''">
          AND graph_rows.direction = (#{query.direction} COLLATE utf8mb4_general_ci)
        </if>
        ORDER BY graph_rows.trxDate DESC, graph_rows.bankStatementId DESC
    </select>

    <select id="countSubjectByObjectKey" resultType="int">
        SELECT COUNT(1)
        FROM lx_fund_flow_subject_node
        WHERE object_key = (#{objectKey} COLLATE utf8mb4_general_ci)
    </select>

    <insert id="insertManualSubject">
        INSERT IGNORE INTO lx_fund_flow_subject_node (
            object_key,
            idnocfno,
            name,
            idno_type,
            source_type
        ) VALUES (
            #{objectKey},
            #{idNo},
            #{name},
            CASE
                WHEN #{idNo} IS NULL OR TRIM(#{idNo}) = '' THEN 'NAME_PROXY'
                ELSE 'PERSON'
            END,
            'MANUAL'
        )
    </insert>

    <insert id="insertManualEdge">
        INSERT INTO lx_fund_flow_manual_edge (
            object_key,
            from_object_key,
            to_object_key,
            from_name,
            to_name,
            amount,
            transaction_count,
            direction,
            relation_desc,
            source_desc,
            remark,
            source_type,
            created_by,
            updated_by
        ) VALUES (
            #{objectKey},
            #{dto.fromObjectKey},
            #{dto.toObjectKey},
            #{dto.fromName},
            #{dto.toName},
            #{dto.amount},
            #{dto.transactionCount},
            #{dto.direction},
            #{dto.relationDesc},
            #{dto.sourceDesc},
            #{dto.remark},
            'MANUAL',
            #{operator},
            #{operator}
        )
    </insert>
</mapper>
