package incheon.com.security.web;

import incheon.com.security.service.MaintenanceLoginService;
import incheon.com.security.service.SecurityUserService;
import incheon.com.security.service.UserRoleAssignService;
import incheon.com.security.vo.LoginVO;
import incheon.com.security.vo.UserAuthrtVO;
import incheon.com.security.vo.UserRoleVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 로그인 컨트롤러
 * AuthenticationFilter와 연동하여 세션 기반 로그인 처리
 */
@Slf4j
@Controller
@RequiredArgsConstructor
@RequestMapping("/auth")
public class LoginController {

    private static final String AGS_SYS_CD = "AGS";
    private static final String AGS_USER_ROLE_CD = "ROLE_AGS_USER";

    private final SecurityUserService securityUserService;
    private final UserRoleAssignService userRoleAssignService;
    private final MaintenanceLoginService maintenanceLoginService;
    private final Environment environment;

    @Value("${Globals.maintenance.id}")
    private String maintenanceId;

    @Value("${Globals.maintenance.password}")
    private String maintenancePassword;

    /**
     * 운영 프로필인지 확인
     */
    private boolean isProductionProfile() {
        return Arrays.asList(environment.getActiveProfiles()).contains("prod");
    }

    /**
     * 활성 사용자 목록 조회 (로그인 페이지용)
     * @return 사용자 목록 (userId, userNm, deptNm만 포함)
     */
    @GetMapping("/users.do")
    @ResponseBody
    public List<LoginVO> getActiveUsers() {
        List<LoginVO> users = securityUserService.getAllActiveUsers();

        // 보안을 위해 필요한 필드만 반환
        return users.stream()
                .map(user -> {
                    LoginVO simpleUser = new LoginVO();
                    simpleUser.setUserId(user.getUserId());
                    simpleUser.setUserNm(user.getUserNm());
                    simpleUser.setDeptCd(user.getDeptCd());
                    simpleUser.setDeptNm(user.getDeptNm());
                    return simpleUser;
                })
                .collect(Collectors.toList());
    }

    /**
     * 로그인 처리
     */
    @PostMapping("/loginProcess.do")
    public String loginProcess(@RequestParam("id") String userId,
                             @RequestParam("maintPwd") String maintPwd,
                             @RequestParam(value = "returnUrl", required = false) String returnUrl,
                             HttpServletRequest request) {

        log.info("로그인 시도 - userId: {}", userId);

        // 유지보수 패스워드 검증
        if (!maintenancePassword.equals(maintPwd)) {
            log.warn("유지보수 패스워드 불일치 - userId: {}, IP: {}", userId, request.getRemoteAddr());
            return "redirect:/?error=wrong_password";
        }

        LoginVO user = securityUserService.getUserWithAuthrts(userId);

        if (user != null) {
            // 세션에 사용자 정보 저장
            HttpSession session = request.getSession();

            // 사용자 정보 복사 및 로그인 시간 설정
            LoginVO sessionUser = copyUserForSession(user);
            session.setAttribute("loginVO", sessionUser);

            // 로그인 일시 업데이트
            securityUserService.updateUserSession(userId);

            log.info("로그인 성공: {} ({})", sessionUser.getUserNm(), sessionUser.getUserId());

            // 기본 역할 자동 할당 (개발 환경 - Lazy Initialization)
            // - ROLE_AGS_USER 역할이 없으면 자동 부여
            // - 로그인 시점에 할당하여 메인 페이지 리다이렉트 1회 감소
            boolean roleAssigned = userRoleAssignService.assignRoleIfAbsent(
                    sessionUser.getUserId(), AGS_USER_ROLE_CD, AGS_SYS_CD);
            if (roleAssigned) {
                log.info("[로컬] 기본 역할 자동 할당: userId={}, roleCd={}", sessionUser.getUserId(), AGS_USER_ROLE_CD);
                // 세션 권한 정보 갱신
                securityUserService.refreshSessionAuthrts(session, sessionUser.getUserId());
            }

            // returnUrl이 있으면 해당 페이지로, 없으면 메인 페이지로 리다이렉트
            if (returnUrl != null && !returnUrl.isEmpty() && !returnUrl.equals("/")) {
                log.info("[개발 전용] 이전 페이지로 복귀: {}", returnUrl);
                return "redirect:" + returnUrl;
            }

            // 메인 페이지로 리다이렉트
            return "redirect:/?success=login";

        } else {
            log.warn("로그인 실패: 사용자를 찾을 수 없음 - {}", userId);
            return "redirect:/?error=user_not_found";
        }
    }
    
    /**
     * 로그아웃 처리
     */
    @PostMapping("/logout.do")
    public String logout(HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        if (session != null) {
            LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
            if (loginVO != null) {
                log.info("로그아웃: {} ({})", loginVO.getUserNm(), loginVO.getUserId());
            }

            // 세션 무효화
            session.invalidate();
        }

        return "redirect:/?success=logout";
    }

    /**
     * 유지보수 로그인 처리 (개발 환경 전용)
     * - prod 환경에서는 차단
     * - DB 전체 역할/권한으로 세션 구성
     */
    @PostMapping("/maintenanceLogin.do")
    public String maintenanceLogin(
            @RequestParam("maintPwd") String maintPwd,
            HttpServletRequest request) {

        log.info("[MAINTENANCE] 로그인 시도 - id: {}", maintenanceId);

        if (isProductionProfile()) {
            log.warn("[MAINTENANCE] 운영 환경에서 유지보수 로그인 시도 차단 - IP: {}", request.getRemoteAddr());
            return "redirect:/?error=maintenance_blocked";
        }

        if (!maintenancePassword.equals(maintPwd)) {
            log.warn("[MAINTENANCE] 패스워드 불일치 - IP: {}", request.getRemoteAddr());
            return "redirect:/?error=wrong_password";
        }

        try {
            // DB 역할 전체 조회 → 역할 기반 권한 조회
            List<UserRoleVO> allRoles = maintenanceLoginService.getAllActiveRoles();
            List<String> allRoleCds = allRoles.stream()
                    .map(UserRoleVO::getRoleCd)
                    .collect(Collectors.toList());
            List<UserAuthrtVO> allAuthrts = maintenanceLoginService.getAuthrtsByRoleCds(allRoleCds);

            List<String> allSysCds = allRoles.stream()
                    .map(UserRoleVO::getSysCd)
                    .distinct()
                    .sorted()
                    .collect(Collectors.toList());

            // 세션용 LoginVO 구성
            LoginVO maintenanceUser = new LoginVO();
            maintenanceUser.setUserId(maintenanceId);
            maintenanceUser.setUserNm("유지보수(" + maintenanceId + ")");
            maintenanceUser.setUserStcd("M");
            maintenanceUser.setDeptNm("유지보수팀");
            maintenanceUser.setDeptWholNm("유지보수팀");
            maintenanceUser.setUserUnqId(maintenanceId);
            maintenanceUser.setDeptCd("9999999");
            maintenanceUser.setJbgdCd("99999");
            maintenanceUser.setJbgdNm("유지보수");
            maintenanceUser.setRprsInstCd("9999999");
            maintenanceUser.setRprsInstNm("유지보수");
            maintenanceUser.setRoadMngInstCd("9999999");
            maintenanceUser.setRoadMngInstNm("유지보수");
            maintenanceUser.setEmlAddr("maintenance@all4land.com");
            maintenanceUser.setOfcTelno("");
            maintenanceUser.setCurrentSysCd("AGS");

            maintenanceUser.setUserRoles(allRoles);
            maintenanceUser.setTempUserRoles(new ArrayList<>());
            maintenanceUser.setUserAuthrts(allAuthrts);
            maintenanceUser.setAuthorities(allAuthrts.stream()
                    .map(authrt -> (GrantedAuthority) new SimpleGrantedAuthority(authrt.toAuthority()))
                    .distinct()
                    .collect(Collectors.toList()));
            maintenanceUser.setActiveSysCds(allSysCds);

            // 선택된 역할 기반으로 관리자 권한 동적 세팅
            boolean isSuperAdmin = allRoles.stream()
                    .anyMatch(r -> "ROLTYP001".equals(r.getRoleTypeCd()));
            List<String> adminSysCds = allRoles.stream()
                    .filter(r -> "ROLTYP002".equals(r.getRoleTypeCd()))
                    .map(UserRoleVO::getSysCd)
                    .filter(Objects::nonNull)
                    .distinct()
                    .sorted()
                    .collect(Collectors.toList());
            maintenanceUser.setSuperAdmin(isSuperAdmin);
            maintenanceUser.setAdminSysCds(adminSysCds);
            maintenanceUser.setLoginTime(new Date());

            HttpSession session = request.getSession();
            session.setAttribute("loginVO", maintenanceUser);

            log.info("[MAINTENANCE] 로그인 성공 - id: {}, IP: {}, roles: {}개, authrts: {}개",
                    maintenanceId, request.getRemoteAddr(), allRoleCds.size(), allAuthrts.size());

            return "redirect:/?success=login";

        } catch (Exception e) {
            log.error("[MAINTENANCE] 유지보수 로그인 처리 중 오류", e);
            return "redirect:/?error=maintenance_error";
        }
    }

    /**
     * 사용자 정보를 세션용으로 복사 (로그인 시간 설정 포함)
     */
    private LoginVO copyUserForSession(LoginVO user) {
        LoginVO sessionUser = new LoginVO();

        // 기본 사용자 정보
        sessionUser.setUserUnqId(user.getUserUnqId());
        sessionUser.setUserId(user.getUserId());
        sessionUser.setUserStcd(user.getUserStcd());
        sessionUser.setUserNm(user.getUserNm());

        // 조직 정보
        sessionUser.setDeptCd(user.getDeptCd());
        sessionUser.setDeptNm(user.getDeptNm());
        sessionUser.setDeptWholNm(user.getDeptWholNm());
        sessionUser.setJbgdCd(user.getJbgdCd());
        sessionUser.setJbgdNm(user.getJbgdNm());
        sessionUser.setJbpsCd(user.getJbpsCd());
        sessionUser.setJbpsNm(user.getJbpsNm());

        // 대표기관 정보
        sessionUser.setRprsInstCd(user.getRprsInstCd());
        sessionUser.setRprsInstNm(user.getRprsInstNm());
        sessionUser.setRoadMngInstCd(user.getRoadMngInstCd());
        sessionUser.setRoadMngInstNm(user.getRoadMngInstNm());

        // 연락처 정보
        sessionUser.setEmlAddr(user.getEmlAddr());
        sessionUser.setOfcTelno(user.getOfcTelno());
        sessionUser.setMblTelno(user.getMblTelno());

        // 시스템 정보
        sessionUser.setFrstRegId(user.getFrstRegId());
        sessionUser.setFrstRegDt(user.getFrstRegDt());
        sessionUser.setLastMdfcnId(user.getLastMdfcnId());
        sessionUser.setLastMdfcnDt(user.getLastMdfcnDt());

        // 권한 정보 (기존)
        sessionUser.setGroupId(user.getGroupId());

        // 권한 정보 (시스템별)
        sessionUser.setUserAuthrts(user.getUserAuthrts());
        sessionUser.setUserRoles(user.getUserRoles());
        sessionUser.setTempUserRoles(user.getTempUserRoles());
        sessionUser.setAuthorities(user.getAuthorities());
        sessionUser.setCurrentSysCd(user.getCurrentSysCd());
        sessionUser.setActiveSysCds(user.getActiveSysCds());

        // 관리자 권한 정보
        sessionUser.setSuperAdmin(user.isSuperAdmin());
        sessionUser.setAdminSysCds(user.getAdminSysCds());

        // 로그인 시간 설정
        sessionUser.setLoginTime(new Date());

        return sessionUser;
    }
}
