package com.zioinfo.hrm.auth;

import com.zioinfo.hrm.auth.dto.ChangePasswordRequest;
import com.zioinfo.hrm.auth.dto.OtpConfirmRequest;
import com.zioinfo.hrm.auth.dto.OtpSetupResponse;
import com.zioinfo.hrm.auth.dto.OtpVerifyRequest;
import com.zioinfo.hrm.common.ApiResponse;
import com.zioinfo.hrm.uiws.auth.OtpAuthService;
import com.zioinfo.hrm.uiws.auth.TwoFactorService;
import com.zioinfo.hrm.uiws.common.UiwsApiException;
import com.zioinfo.hrm.uiws.common.UiwsErrorCode;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * HRM 인증 컨트롤러.
 * - /login: 2FA off 면 { token, type, twofa:"false" }.
 *           OTP on 이면 { twofa:"true", verifyToken, verifyMethod:(OTP|OTP_SETUP), secret?, otpAuthUri?, qrImage? }.
 *           이메일 2FA on 이면 { twofa:"true", verifyToken, step, maskedEmail }.
 * - /verify-otp: (UIMS 방식) verify-token + 6자리 → access/refresh(최초 로그인이면 등록 확정).
 * - /verify: (이메일 2FA) verify-token + 인증코드 → access/refresh.
 * 기존 클라이언트(2FA off)는 응답에 token 보존 → 회귀 0.
 */
@RestController
@RequestMapping("/api/hrm/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;
    private final TwoFactorService twoFactorService;
    private final OtpAuthService otpAuthService;
    private final JwtUtil jwtUtil;

    @PostMapping("/login")
    public ApiResponse<Map<String, String>> login(@RequestBody LoginRequest req) {
        return ApiResponse.ok(authService.login(req.username(), req.password()));
    }

    /** 이메일 2FA 이식: 2차 인증 코드 검증 → access/refresh 발급. */
    @PostMapping("/verify")
    public ApiResponse<Map<String, String>> verify(@RequestBody VerifyRequest req) {
        return ApiResponse.ok(twoFactorService.verify(req.verifyToken(), req.code()));
    }

    /** TOTP 이식: 로그인 2단계 6자리 검증 → access/refresh 발급(최초 로그인이면 등록 확정). */
    @PostMapping("/verify-otp")
    public ApiResponse<Map<String, String>> verifyOtp(@Valid @RequestBody OtpVerifyRequest req) {
        return ApiResponse.ok(otpAuthService.verifyOtp(req.verifyToken(), req.code()));
    }

    @GetMapping("/me")
    public ApiResponse<Map<String, Object>> me(@RequestHeader("Authorization") String header) {
        String token = header.replace("Bearer ", "");
        return ApiResponse.ok(authService.me(token));
    }

    // ── 마이페이지: OTP 등록/재설정/해제 + 비밀번호 변경 (본인, access 토큰 필요) ──────────

    /** 마이페이지 OTP 등록/재설정 시작 → { secret, otpAuthUri, qrImage }(이 응답에서만 시크릿/QR 노출). */
    @PostMapping("/otp/setup")
    public ApiResponse<OtpSetupResponse> otpSetup(@RequestHeader("Authorization") String header) {
        return ApiResponse.ok(otpAuthService.setup(requireUser(header)));
    }

    /** 마이페이지 OTP 확인·활성화(앱 6자리 코드). */
    @PostMapping("/otp/confirm")
    public ApiResponse<Map<String, String>> otpConfirm(@RequestHeader("Authorization") String header,
                                                       @Valid @RequestBody OtpConfirmRequest req) {
        otpAuthService.confirm(requireUser(header), req.code());
        return ApiResponse.ok(Map.of("result", "ok"));
    }

    /** 마이페이지 OTP 해제. */
    @PostMapping("/otp/disable")
    public ApiResponse<Map<String, String>> otpDisable(@RequestHeader("Authorization") String header) {
        otpAuthService.disable(requireUser(header));
        return ApiResponse.ok(Map.of("result", "ok"));
    }

    /** 마이페이지 비밀번호 변경(현재 비번 검증 + BCrypt). 새 비번은 응답/로그 미포함. */
    @PostMapping("/change-password")
    public ApiResponse<Map<String, String>> changePassword(@RequestHeader("Authorization") String header,
                                                           @Valid @RequestBody ChangePasswordRequest req) {
        authService.changePassword(requireUser(header), req);
        return ApiResponse.ok(Map.of("result", "ok"));
    }

    /**
     * Authorization 헤더에서 인증 사용자를 해석한다. verify-token(2fa 단계용)은 거부.
     * (/api/hrm/auth/** 는 permitAll 이라 필터 인증이 없으므로 여기서 access 토큰을 명시 검증.)
     */
    private String requireUser(String header) {
        String token = header == null ? "" : header.replace("Bearer ", "").trim();
        if (token.isEmpty() || jwtUtil.isVerifyToken(token) || !jwtUtil.isValid(token)) {
            throw new UiwsApiException(UiwsErrorCode.UNAUTHORIZED);
        }
        return jwtUtil.getUsername(token);
    }

    record LoginRequest(String username, String password) {}

    record VerifyRequest(String verifyToken, String code) {}
}
