package com.zioinfo.hrm.auth.mapper;

import com.zioinfo.hrm.auth.HrmUser;
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.time.LocalDateTime;

/**
 * HRM 운영자 계정 매퍼.
 * 기존 메서드(findByUsername/insert)에 UIWS 2FA·로그인 보조기능 이식 메서드를 추가.
 * 대상 테이블 hrm_users (컬럼 active — pms_user.is_active 와 다름).
 */
@Mapper
public interface UserMapper {

    HrmUser findByUsername(@Param("username") String username);

    int insert(HrmUser user);

    /** 회원가입(승인 대기): username·password_hash·display_name·email + role='VIEWER'·approved=false. */
    int insertSignup(HrmUser user);

    // ── UIWS 로그인 보조기능 이식(회원가입·아이디찾기·비번초기화) ───────────────

    /** 가입 중복 검사: username 존재 여부. */
    @Select("SELECT COUNT(1) FROM hrm_users WHERE username = #{username}")
    int countByUsername(@Param("username") String username);

    /** 가입 중복 검사: email 존재 여부(enumeration 최소화 — 내부 사용). */
    @Select("SELECT COUNT(1) FROM hrm_users WHERE email = #{email}")
    int countByEmail(@Param("email") String email);

    /** 아이디찾기: 이름(display_name)·이메일 일치 사용자(존재 시 마스킹 반환). */
    @Select("""
            SELECT id, username, password_hash, role, active, created_at,
                   display_name, email,
                   email_verify_code, email_verify_expire, login_fail_count, locked, otp_secret,
                   approved, pw_change_yn
            FROM hrm_users
            WHERE display_name = #{displayName} AND email = #{email}
            ORDER BY id LIMIT 1
            """)
    HrmUser findByDisplayNameAndEmail(@Param("displayName") String displayName,
                                      @Param("email") String email);

    /** 비번초기화: username·email 동시 일치 검증용. */
    @Select("""
            SELECT id, username, password_hash, role, active, created_at,
                   display_name, email,
                   email_verify_code, email_verify_expire, login_fail_count, locked, otp_secret,
                   approved, pw_change_yn
            FROM hrm_users
            WHERE username = #{username} AND email = #{email}
            """)
    HrmUser findByUsernameAndEmail(@Param("username") String username,
                                   @Param("email") String email);

    /** 비번초기화: 임시비번 적용 + 변경유도 + 잠금/실패카운트 해제(멱등 UPDATE). */
    @Update("""
            UPDATE hrm_users
            SET password_hash = #{passwordHash}, pw_change_yn = true,
                locked = false, login_fail_count = 0
            WHERE username = #{username}
            """)
    int applyTempPassword(@Param("username") String username,
                          @Param("passwordHash") String passwordHash);

    // ── UIWS 2FA 이식: 실패 카운트/잠금/인증코드 갱신 (멱등 UPDATE) ───────────────

    /** 로그인 성공 시 실패 카운트 초기화. */
    @Update("UPDATE hrm_users SET login_fail_count = 0 WHERE username = #{username}")
    int resetLoginFail(@Param("username") String username);

    /** 로그인 실패 누적(+1) 및 임계 도달 시 잠금. */
    @Update("""
            UPDATE hrm_users
            SET login_fail_count = COALESCE(login_fail_count, 0) + 1,
                locked = (COALESCE(login_fail_count, 0) + 1 >= #{maxFail})
            WHERE username = #{username}
            """)
    int incrementLoginFail(@Param("username") String username, @Param("maxFail") int maxFail);

    /** 1차 통과 시 이메일 인증코드/만료 저장(verify 단계에서 검증). */
    @Update("""
            UPDATE hrm_users
            SET email_verify_code = #{code}, email_verify_expire = #{expire}, login_fail_count = 0
            WHERE username = #{username}
            """)
    int saveEmailCode(@Param("username") String username,
                      @Param("code") String code,
                      @Param("expire") LocalDateTime expire);

    /** 2차 검증 성공 시 코드 폐기. */
    @Update("UPDATE hrm_users SET email_verify_code = NULL, email_verify_expire = NULL WHERE username = #{username}")
    int clearEmailCode(@Param("username") String username);

    /** 관리자 잠금 해제(실패 카운트/잠금 초기화). */
    @Update("UPDATE hrm_users SET locked = false, login_fail_count = 0 WHERE username = #{username}")
    int unlock(@Param("username") String username);

    /**
     * BCrypt 비밀번호 해시 갱신(username 기준). 평문은 절대 저장하지 않는다.
     * 마이페이지 비밀번호 변경 + AdminPasswordSeeder(env 재시드) 공용.
     */
    @Update("UPDATE hrm_users SET password_hash = #{passwordHash} WHERE username = #{username}")
    int updatePasswordByUsername(@Param("username") String username,
                                 @Param("passwordHash") String passwordHash);

    // ── TOTP(OTP 2차 인증) 이식 (멱등 UPDATE) ────────────────────────────────────

    /** 보류 시크릿 저장(등록 확정 전). otp_enabled 은 건드리지 않는다(verify/confirm 에서 확정). */
    @Update("UPDATE hrm_users SET otp_secret = #{secret} WHERE username = #{username}")
    int updateOtpSecret(@Param("username") String username, @Param("secret") String secret);

    /** 등록 확정: otp_enabled=true (시크릿은 유지). */
    @Update("UPDATE hrm_users SET otp_enabled = true WHERE username = #{username}")
    int enableOtp(@Param("username") String username);

    /** 마이페이지 해제: 시크릿 폐기 + otp_enabled=false. */
    @Update("UPDATE hrm_users SET otp_secret = NULL, otp_enabled = false WHERE username = #{username}")
    int disableOtp(@Param("username") String username);
}
