package com.zioinfo.kintex.system.sysuser;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;
import java.util.Map;

/**
 * 시스템관리 — 사용자 조회/관리 매퍼. 보안 불변(계약 §0-3): password_hash·otp_secret 은 절대 select 안 함.
 */
@Mapper
public interface SysUserMapper {

    /** 전역 역할 코드(SystemAccessGuard 게이트). 없으면 null. */
    @Select("SELECT role_code FROM app_user WHERE id = #{userId}")
    String findRoleCode(@Param("userId") String userId);

    /** 사용자 목록(검색·페이징) — 민감 컬럼 제외. 테넌트 스코프(§8-2). */
    @Select("""
            <script>
            SELECT id AS "userId", email, display_name AS "displayName", hall_manager AS "hallManager",
                   role_code AS "roleCode", dept_id AS "deptId", status, otp_enabled AS "otpEnabled",
                   to_char(last_login_at AT TIME ZONE 'UTC','YYYY-MM-DD"T"HH24:MI:SS"Z"') AS "lastLoginAt"
            FROM app_user
            <where>
              AND tenant_id = #{tenantId}
              <if test="keyword != null and keyword != ''">
                AND (email ILIKE '%'||#{keyword}||'%' OR display_name ILIKE '%'||#{keyword}||'%')
              </if>
              <if test="status != null and status != ''">AND status = #{status}</if>
              <if test="roleCode != null and roleCode != ''">AND role_code = #{roleCode}</if>
            </where>
            ORDER BY created_at DESC
            LIMIT #{size} OFFSET #{offset}
            </script>
            """)
    List<Map<String, Object>> search(@Param("tenantId") String tenantId,
                                     @Param("keyword") String keyword, @Param("status") String status,
                                     @Param("roleCode") String roleCode,
                                     @Param("size") int size, @Param("offset") int offset);

    @Select("""
            <script>
            SELECT count(*) FROM app_user
            <where>
              AND tenant_id = #{tenantId}
              <if test="keyword != null and keyword != ''">
                AND (email ILIKE '%'||#{keyword}||'%' OR display_name ILIKE '%'||#{keyword}||'%')
              </if>
              <if test="status != null and status != ''">AND status = #{status}</if>
              <if test="roleCode != null and roleCode != ''">AND role_code = #{roleCode}</if>
            </where>
            </script>
            """)
    long count(@Param("tenantId") String tenantId,
               @Param("keyword") String keyword, @Param("status") String status,
               @Param("roleCode") String roleCode);

    @Select("""
            SELECT id AS "userId", email, display_name AS "displayName", hall_manager AS "hallManager",
                   role_code AS "roleCode", dept_id AS "deptId", status, otp_enabled AS "otpEnabled"
            FROM app_user WHERE id = #{userId}
            """)
    Map<String, Object> findById(@Param("userId") String userId);

    @org.apache.ibatis.annotations.Insert("""
            INSERT INTO app_user (id, email, display_name, password_hash, hall_manager,
                                  role_code, dept_id, status, verify_method, tenant_id)
            VALUES (#{userId}, #{email}, #{displayName}, #{passwordHash}, #{hallManager},
                    #{roleCode}, #{deptId}, 'ACTIVE', 'EMAIL', #{tenantId})
            """)
    int insert(Map<String, Object> p);

    @Update("""
            UPDATE app_user SET display_name = #{displayName}, role_code = #{roleCode},
                   dept_id = #{deptId}, hall_manager = #{hallManager}, updated_at = now()
            WHERE id = #{userId}
            """)
    int update(Map<String, Object> p);

    @Update("UPDATE app_user SET status = #{status}, updated_at = now() WHERE id = #{userId}")
    int updateStatus(@Param("userId") String userId, @Param("status") String status);

    @Update("UPDATE app_user SET password_hash = #{passwordHash}, updated_at = now() WHERE id = #{userId}")
    int updatePassword(@Param("userId") String userId, @Param("passwordHash") String passwordHash);
}
