package gc.mda.kcg.auth;

import gc.mda.kcg.auth.dto.LoginRequest;
import gc.mda.kcg.auth.dto.UserInfoResponse;
import gc.mda.kcg.auth.provider.AuthProvider;
import gc.mda.kcg.config.AppProperties;
import gc.mda.kcg.menu.MenuConfigService;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

    private final AuthService authService;
    private final JwtService jwtService;
    private final AppProperties appProperties;
    private final MenuConfigService menuConfigService;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest req,
                                    HttpServletRequest http,
                                    HttpServletResponse res) {
        String ip = extractIp(http);
        String ua = http.getHeader("User-Agent");
        try {
            AuthService.AuthResult result = authService.login(req.account(), req.password(), ip, ua);
            User user = result.user();
            var roles = authService.getUserInfo(user.getUserId()).roles();

            String token = jwtService.generateToken(user.getUserId(), user.getUserAcnt(), user.getUserNm(), roles);

            Cookie cookie = new Cookie(JwtAuthFilter.COOKIE_NAME, token);
            cookie.setHttpOnly(true);
            cookie.setPath("/");
            cookie.setMaxAge((int) (jwtService.getExpirationMs() / 1000));
            // Production에서는 secure=true 권장 (HTTPS)
            cookie.setSecure(false);
            res.addCookie(cookie);

            return ResponseEntity.ok(toUserInfo(user.getUserId()));

        } catch (AuthProvider.AuthenticationException e) {
            log.warn("Login failed for {}: {}", req.account(), e.getReason());
            return ResponseEntity.status(401).body(Map.of(
                    "error", "LOGIN_FAILED",
                    "reason", e.getReason()
            ));
        }
    }

    @PostMapping("/logout")
    public ResponseEntity<?> logout(HttpServletRequest http, HttpServletResponse res) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && auth.getPrincipal() instanceof AuthPrincipal principal) {
            authService.logout(principal.getUserId(), principal.getUserAcnt(), extractIp(http));
        }

        Cookie cookie = new Cookie(JwtAuthFilter.COOKIE_NAME, "");
        cookie.setHttpOnly(true);
        cookie.setPath("/");
        cookie.setMaxAge(0);
        res.addCookie(cookie);

        return ResponseEntity.ok(Map.of("ok", true));
    }

    @GetMapping("/me")
    public ResponseEntity<?> me() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth == null || !(auth.getPrincipal() instanceof AuthPrincipal principal)) {
            return ResponseEntity.status(401).body(Map.of("error", "UNAUTHENTICATED"));
        }
        return ResponseEntity.ok(toUserInfo(principal.getUserId()));
    }

    private UserInfoResponse toUserInfo(java.util.UUID userId) {
        AuthService.UserInfo info = authService.getUserInfo(userId);
        User u = info.user();
        return new UserInfoResponse(
                u.getUserId().toString(),
                u.getUserAcnt(),
                u.getUserNm(),
                u.getRnkpNm(),
                u.getEmail(),
                u.getUserSttsCd(),
                u.getAuthProvider(),
                info.roles(),
                info.permissions(),
                menuConfigService.getActiveMenuConfig()
        );
    }

    private String extractIp(HttpServletRequest req) {
        String fwd = req.getHeader("X-Forwarded-For");
        if (fwd != null && !fwd.isBlank()) return fwd.split(",")[0].trim();
        return req.getRemoteAddr();
    }
}
