<?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.microservices.zone.member.mapper.ZonePointsAccountMapper">

    <resultMap type="ZonePointsAccount" id="ZonePointsAccountResult">
        <result property="id" column="id"/>
        <result property="userId" column="user_id"/>
        <result property="zoneId" column="zone_id"/>
        <result property="totalPoints" column="total_points"/>
        <result property="totalEarnedPoints" column="total_earned_points"/>
        <result property="totalConsumedPoints" column="total_consumed_points"/>
        <result property="availablePoints" column="available_points"/>
        <result property="frozenPoints" column="frozen_points"/>
        <result property="deptId" column="dept_id"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
    </resultMap>

    <sql id="selectZonePointsAccountVo">
        select id, user_id, zone_id, total_points, total_earned_points, total_consumed_points,
               available_points, frozen_points, dept_id,
               create_by, create_time, update_by, update_time
        from zone_points_account
    </sql>

    <sql id="selectZonePointsAccountAliasVo">
        select zpa.id, zpa.user_id, zpa.zone_id, zpa.total_points, zpa.total_earned_points, zpa.total_consumed_points,
               zpa.available_points, zpa.frozen_points, zpa.dept_id, zpa.create_by, zpa.create_time, zpa.update_by, zpa.update_time
        from zone_points_account zpa
    </sql>

    <select id="selectZonePointsAccountList" parameterType="ZonePointsAccount" resultMap="ZonePointsAccountResult">
        <include refid="selectZonePointsAccountAliasVo"/>
        <where>
            <if test="userId != null">and zpa.user_id = #{userId}</if>
            <if test="zoneId != null">and zpa.zone_id = #{zoneId}</if>
            ${params.dataScope}
        </where>
    </select>

    <select id="selectZonePointsAccountById" parameterType="Long" resultMap="ZonePointsAccountResult">
        <include refid="selectZonePointsAccountVo"/>
        where id = #{id}
    </select>

    <select id="selectZonePointsAccountByUserIdAndZoneId" resultMap="ZonePointsAccountResult">
        <include refid="selectZonePointsAccountVo"/>
        where user_id = #{userId} and zone_id = #{zoneId}
    </select>

    <!-- 锁定行获取账户信息，用于并发安全更新 -->
    <select id="selectZonePointsAccountByIdForUpdate" parameterType="Long" resultMap="ZonePointsAccountResult">
        <include refid="selectZonePointsAccountVo"/>
        where id = #{id} for update
    </select>

    <insert id="insertZonePointsAccount" parameterType="ZonePointsAccount" useGeneratedKeys="true" keyProperty="id">
        insert into zone_points_account
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="userId != null">user_id,</if>
            <if test="zoneId != null">zone_id,</if>
            <if test="totalPoints != null">total_points,</if>
            <if test="totalEarnedPoints != null">total_earned_points,</if>
            <if test="totalConsumedPoints != null">total_consumed_points,</if>
            <if test="availablePoints != null">available_points,</if>
            <if test="frozenPoints != null">frozen_points,</if>
            <if test="deptId != null">dept_id,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="userId != null">#{userId},</if>
            <if test="zoneId != null">#{zoneId},</if>
            <if test="totalPoints != null">#{totalPoints},</if>
            <if test="totalEarnedPoints != null">#{totalEarnedPoints},</if>
            <if test="totalConsumedPoints != null">#{totalConsumedPoints},</if>
            <if test="availablePoints != null">#{availablePoints},</if>
            <if test="frozenPoints != null">#{frozenPoints},</if>
            <if test="deptId != null">#{deptId},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
        </trim>
    </insert>

    <update id="updateZonePointsAccount" parameterType="ZonePointsAccount">
        update zone_points_account
        <trim prefix="SET" suffixOverrides=",">
            <if test="userId != null">user_id = #{userId},</if>
            <if test="zoneId != null">zone_id = #{zoneId},</if>
            <if test="totalPoints != null">total_points = #{totalPoints},</if>
            <if test="totalEarnedPoints != null">total_earned_points = #{totalEarnedPoints},</if>
            <if test="totalConsumedPoints != null">total_consumed_points = #{totalConsumedPoints},</if>
            <if test="availablePoints != null">available_points = #{availablePoints},</if>
            <if test="frozenPoints != null">frozen_points = #{frozenPoints},</if>
            <if test="deptId != null">dept_id = #{deptId},</if>
            <if test="createBy != null">create_by = #{createBy},</if>
            <if test="createTime != null">create_time = #{createTime},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
        </trim>
        where id = #{id}
    </update>

    <!-- 原子增加积分（并发安全） -->
    <update id="addPointsAtomic">
        update zone_points_account
        set total_points = total_points + #{addPoints},
            total_earned_points = total_earned_points + #{addPoints},
            available_points = available_points + #{addPoints},
            update_time = now()
        where id = #{id}
    </update>

    <!-- 原子扣除积分（并发安全） -->
    <update id="deductPointsAtomic">
        update zone_points_account
        set total_points = total_points - #{deductPoints},
            total_consumed_points = total_consumed_points + #{deductPoints},
            available_points = available_points - #{deductPoints},
            update_time = now()
        where id = #{id} and available_points >= #{deductPoints}
    </update>

    <update id="freezePointsAtomic">
        update zone_points_account
        set available_points = available_points - #{freezePoints},
            frozen_points = frozen_points + #{freezePoints},
            update_time = now()
        where id = #{id} and available_points >= #{freezePoints}
    </update>

    <update id="unfreezePointsAtomic">
        update zone_points_account
        set available_points = available_points + #{unfreezePoints},
            frozen_points = frozen_points - #{unfreezePoints},
            update_time = now()
        where id = #{id} and frozen_points >= #{unfreezePoints}
    </update>

    <!-- 原子扣减冻结积分（并发安全），申请通过时从冻结积分中正式扣除 -->
    <update id="deductFrozenPointsAtomic">
        update zone_points_account
        set total_points = total_points - #{deductPoints},
            total_consumed_points = total_consumed_points + #{deductPoints},
            frozen_points = frozen_points - #{deductPoints},
            update_time = now()
        where id = #{id} and frozen_points >= #{deductPoints}
    </update>

    <delete id="deleteZonePointsAccountById" parameterType="Long">
        delete from zone_points_account where id = #{id}
    </delete>

    <delete id="deleteZonePointsAccountByIds" parameterType="String">
        delete from zone_points_account where id in
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>
</mapper>