package com.zioinfo.kintex.security;

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.OffsetDateTime;
import java.util.Map;

/**
 * 계정 보안 매퍼 — 2차 인증(OTP)·로그인 실패 잠금 상태. app_user 순증 컬럼 접근.
 * 보안 불변(계약 §0-3): password_hash·otp_secret 은 인증/검증 경로에서만 조회하며 응답 DTO로 노출 금지.
 */
@Mapper
public interface AccountSecurityMapper {

    /** 이메일 → 인증+보안 행(자격검증·2FA 분기용). 없으면 null. */
    @Select("""
            SELECT id AS "userId", display_name AS "displayName", password_hash AS "passwordHash",
                   hall_manager AS "hallManager", otp_enabled AS "otpEnabled", otp_secret AS "otpSecret",
                   role_code AS "roleCode", tenant_id AS "tenantId",
                   failed_login_count AS "failedCount", locked_until AS "lockedUntil"
            FROM app_user WHERE email = #{email} AND status = 'ACTIVE'
            """)
    Map<String, Object> findAuthSecurityByEmail(@Param("email") String email);

    /** userId → 보안 요약(마이페이지 OTP 상태·발급 라벨). */
    @Select("""
            SELECT id AS "userId", email, display_name AS "displayName", hall_manager AS "hallManager",
                   otp_enabled AS "otpEnabled", otp_secret AS "otpSecret", role_code AS "roleCode",
                   tenant_id AS "tenantId"
            FROM app_user WHERE id = #{userId}
            """)
    Map<String, Object> findSecurityById(@Param("userId") String userId);

    /** OTP 시크릿 저장(등록 시작 — 아직 미활성). */
    @Update("UPDATE app_user SET otp_secret = #{secret}, otp_enabled = false, "
            + "verify_method = 'OTP', updated_at = now() WHERE id = #{userId}")
    int saveOtpSecret(@Param("userId") String userId, @Param("secret") String secret);

    /** OTP 활성(코드 확인 완료) — 최초 활성 시각 기록. */
    @Update("UPDATE app_user SET otp_enabled = true, verify_method = 'OTP', "
            + "otp_verified_at = COALESCE(otp_verified_at, now()), updated_at = now() WHERE id = #{userId}")
    int enableOtp(@Param("userId") String userId);

    /** OTP 초기화(비활성 + 시크릿 폐기 + 검증시각 초기화) — 본인 해제/관리자 리셋. */
    @Update("UPDATE app_user SET otp_secret = NULL, otp_enabled = false, otp_verified_at = NULL, "
            + "verify_method = 'EMAIL', updated_at = now() WHERE id = #{userId}")
    int resetOtp(@Param("userId") String userId);

    /** 로그인 실패 카운트 증가. */
    @Update("UPDATE app_user SET failed_login_count = failed_login_count + 1, updated_at = now() "
            + "WHERE email = #{email}")
    int incrementFailure(@Param("email") String email);

    /** 계정 잠금(임계 초과 시 locked_until 설정). */
    @Update("UPDATE app_user SET locked_until = #{until}, updated_at = now() WHERE email = #{email}")
    int lockUntil(@Param("email") String email, @Param("until") OffsetDateTime until);

    /** 로그인 성공 — 실패 카운트/잠금 해제 + 최근 로그인 기록. */
    @Update("UPDATE app_user SET failed_login_count = 0, locked_until = NULL, "
            + "last_login_at = now(), updated_at = now() WHERE id = #{userId}")
    int clearLoginState(@Param("userId") String userId);
}
