<?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.gameplatform.server.mapper.agent.LinkTaskMapper">
    <resultMap id="LinkTaskMap" type="com.gameplatform.server.model.entity.agent.LinkTask">
        <id property="id" column="id" />
        <result property="batchId" column="batch_id" />
        <result property="agentId" column="agent_id" />
        <result property="codeNo" column="code_no" />
        <result property="tokenHash" column="token_hash" />
        <result property="expireAt" column="expire_at" />
        <result property="status" column="status" />
        <result property="region" column="region" />
        <result property="machineId" column="machine_id" />
        <result property="loginAt" column="login_at" />
        <result property="refundAt" column="refund_at" />
        <result property="revokedAt" column="revoked_at" />
        <result property="createdAt" column="created_at" />
        <result property="updatedAt" column="updated_at" />
        <result property="needRefresh" column="need_refresh" />
        <result property="refreshTime" column="refresh_time" />
        <result property="qrCreatedAt" column="qr_created_at" />
        <result property="qrExpireAt" column="qr_expire_at" />
        <result property="firstRegionSelectAt" column="first_region_select_at" />
        <result property="completedPoints" column="completed_points" />
        <result property="completionImages" column="completion_images" />
    </resultMap>

    <select id="findById" parameterType="long" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE id = #{id}
        LIMIT 1
    </select>

    <select id="findByCodeNo" parameterType="string" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE code_no = #{codeNo}
        LIMIT 1
    </select>

    <select id="findByTokenHash" parameterType="string" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE token_hash = #{tokenHash}
        LIMIT 1
    </select>

    <insert id="insert" parameterType="com.gameplatform.server.model.entity.agent.LinkTask" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO link_task (batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at)
        VALUES (#{batchId}, #{agentId}, #{codeNo}, #{tokenHash}, #{expireAt}, #{status}, #{region}, #{machineId}, #{loginAt}, #{refundAt}, #{revokedAt}, #{needRefresh}, #{refreshTime}, #{qrCreatedAt}, #{qrExpireAt}, #{firstRegionSelectAt})
    </insert>

    <update id="update" parameterType="com.gameplatform.server.model.entity.agent.LinkTask">
        UPDATE link_task
        <set>
            <if test="status != null">status = #{status},</if>
            <if test="region != null">region = #{region},</if>
            <if test="machineId != null">machine_id = #{machineId},</if>
            <if test="loginAt != null">login_at = #{loginAt},</if>
            <if test="refundAt != null">refund_at = #{refundAt},</if>
            <if test="revokedAt != null">revoked_at = #{revokedAt},</if>
            <if test="needRefresh != null">need_refresh = #{needRefresh},</if>
            <if test="refreshTime != null">refresh_time = #{refreshTime},</if>
            <if test="qrCreatedAt != null">qr_created_at = #{qrCreatedAt},</if>
            <if test="qrExpireAt != null">qr_expire_at = #{qrExpireAt},</if>
            <if test="firstRegionSelectAt != null">first_region_select_at = #{firstRegionSelectAt},</if>
            <if test="completedPoints != null">completed_points = #{completedPoints},</if>
            <if test="completionImages != null">completion_images = #{completionImages},</if>
            updated_at = NOW()
        </set>
        WHERE id = #{id}
    </update>

    <update id="updateStatus">
        UPDATE link_task SET status = #{status} WHERE id = #{id}
    </update>

    <update id="updateStatusAndMachine">
        UPDATE link_task 
        SET status = #{status}, region = #{region}, machine_id = #{machineId}, login_at = #{loginAt}
        WHERE id = #{id}
    </update>

    <!-- 仅当新点数更大时更新，减少写冲突和无效更新 -->
    <update id="updatePointsIfGreater">
        UPDATE link_task
        SET completed_points = #{newPoints}, updated_at = NOW()
        WHERE id = #{id}
          AND (completed_points IS NULL OR completed_points &lt; #{newPoints})
    </update>

    <select id="findByAgentId" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE agent_id = #{agentId}
        ORDER BY created_at DESC
        LIMIT #{size} OFFSET #{offset}
    </select>

    <select id="countByAgentId" resultType="long">
        SELECT COUNT(1) FROM link_task WHERE agent_id = #{agentId}
    </select>

    <select id="findByAgentIdAndStatus" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE agent_id = #{agentId} AND status = #{status}
        ORDER BY created_at DESC
        LIMIT #{size} OFFSET #{offset}
    </select>

    <select id="countByAgentIdAndStatus" resultType="long">
        SELECT COUNT(1) FROM link_task WHERE agent_id = #{agentId} AND status = #{status}
    </select>

    <select id="findByBatchId" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE batch_id = #{batchId}
        ORDER BY created_at DESC
        LIMIT #{size} OFFSET #{offset}
    </select>

    <select id="countByBatchId" resultType="long">
        SELECT COUNT(1) FROM link_task WHERE batch_id = #{batchId}
    </select>

    <select id="findExpiredTasks" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE expire_at &lt;= #{expireTime} AND status IN ('NEW', 'USING')
        ORDER BY expire_at ASC
        LIMIT #{size}
    </select>

    <select id="findLinkTasksWithConditions" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        <where>
            agent_id = #{agentId}
            <if test="status != null and status != ''">
                AND status = #{status}
            </if>
            <if test="batchId != null">
                AND batch_id = #{batchId}
            </if>
            <if test="isExpired != null">
                <choose>
                    <when test="isExpired == true">
                        AND expire_at &lt;= NOW()
                    </when>
                    <otherwise>
                        AND expire_at &gt; NOW()
                    </otherwise>
                </choose>
            </if>
        </where>
        <choose>
            <when test="sortBy == 'expireAt'">
                ORDER BY expire_at ${sortDir}
            </when>
            <when test="sortBy == 'updatedAt'">
                ORDER BY updated_at ${sortDir}
            </when>
            <otherwise>
                ORDER BY created_at ${sortDir}
            </otherwise>
        </choose>
        LIMIT #{size} OFFSET #{offset}
    </select>

    <select id="countLinkTasksWithConditions" resultType="long">
        SELECT COUNT(1)
        FROM link_task
        <where>
            agent_id = #{agentId}
            <if test="status != null and status != ''">
                AND status = #{status}
            </if>
            <if test="batchId != null">
                AND batch_id = #{batchId}
            </if>
            <if test="isExpired != null">
                <choose>
                    <when test="isExpired == true">
                        AND expire_at &lt;= NOW()
                    </when>
                    <otherwise>
                        AND expire_at &gt; NOW()
                    </otherwise>
                </choose>
            </if>
        </where>
    </select>

    <delete id="deleteByCodeNo">
        DELETE FROM link_task WHERE code_no = #{codeNo}
    </delete>

    <delete id="deleteByCodeNoAndAgentId">
        DELETE FROM link_task WHERE code_no = #{codeNo} AND agent_id = #{agentId}
    </delete>

    <delete id="batchDeleteByCodeNosAndAgentId">
        DELETE FROM link_task 
        WHERE agent_id = #{agentId} 
        AND code_no IN 
        <foreach collection="codeNos" item="codeNo" open="(" close=")" separator=",">
            #{codeNo}
        </foreach>
    </delete>

    <select id="findByCodeNosAndAgentId" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE agent_id = #{agentId} 
        AND code_no IN 
        <foreach collection="codeNos" item="codeNo" open="(" close=")" separator=",">
            #{codeNo}
        </foreach>
    </select>

    <select id="findByMachineIdAndStatus" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE machine_id = #{machineId} AND status = #{status}
    </select>

    <select id="findByStatusListAndAgentId" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE agent_id = #{agentId} 
        AND status IN 
        <foreach collection="statusList" item="status" open="(" close=")" separator=",">
            #{status}
        </foreach>
        ORDER BY created_at DESC
    </select>

    <select id="countByStatusListAndAgentId" resultType="long">
        SELECT COUNT(1) 
        FROM link_task 
        WHERE agent_id = #{agentId} 
        AND status IN 
        <foreach collection="statusList" item="status" open="(" close=")" separator=",">
            #{status}
        </foreach>
    </select>

    <delete id="batchDeleteByStatusListAndAgentId">
        DELETE FROM link_task 
        WHERE agent_id = #{agentId} 
        AND status IN 
        <foreach collection="statusList" item="status" open="(" close=")" separator=",">
            #{status}
        </foreach>
    </delete>

    <select id="findByStatus" resultMap="LinkTaskMap">
        SELECT id, batch_id, agent_id, code_no, token_hash, expire_at, status, region, machine_id, login_at, refund_at, revoked_at, created_at, updated_at, need_refresh, refresh_time, qr_created_at, qr_expire_at, first_region_select_at, completed_points, completion_images
        FROM link_task
        WHERE status = #{status}
        ORDER BY created_at ASC
    </select>

    <!-- 原子占用设备，避免并发下同一设备被多个链接占用 -->
    <update id="reserveDeviceIfFree">
        UPDATE link_task lt
        LEFT JOIN (
            SELECT 1 as has_conflict
            FROM link_task x
            WHERE x.machine_id = #{deviceId}
              AND x.status IN ('USING','LOGGED_IN')
              AND x.id &lt;&gt; #{id}
        ) conflict_check ON 1=1
        SET lt.status = 'USING',
            lt.region = #{region},
            lt.machine_id = #{deviceId},
            lt.qr_created_at = NOW(),
            lt.qr_expire_at = DATE_ADD(NOW(), INTERVAL #{qrExpireSeconds} SECOND),
            lt.updated_at = NOW()
        WHERE lt.id = #{id}
          AND conflict_check.has_conflict IS NULL
    </update>

</mapper>
