package incheon.com.security.web;

import incheon.com.security.service.SecurityUserService;
import incheon.com.security.service.UserRoleAssignService;
import incheon.com.security.vo.LoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;

/**
 * SSO 로그인 처리 컨트롤러
 * - sido_connect.jsp에서 SSO_ID 세션 저장 후 호출
 * - SSO_ID로 DB 조회 → loginVO 생성 → target URL로 리다이렉트
 */
@Slf4j
@Controller
@RequiredArgsConstructor
@RequestMapping("/sso")
public class SsoLoginController {

    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;

    @Value("${sso.default.target:/ags/main.do}")
    private String defaultTarget;

    @GetMapping("/login-process.do")
    public String ssoLoginProcess(
            @RequestParam(value = "target", required = false) String target,
            HttpServletRequest request) {

        HttpSession session = request.getSession(false);

        if (session == null) {
            log.warn("[SSO] 세션 없음");
            return "redirect:/magicsso/sso_login_required.jsp";
        }

        String ssoId = (String) session.getAttribute("SSO_ID");
        if (ssoId == null || ssoId.trim().isEmpty()) {
            log.warn("[SSO] SSO_ID 없음");
            session.removeAttribute("SSO_REDIRECT_COUNT");
            return "redirect:/magicsso/sso_login_required.jsp";
        }

        LoginVO user = securityUserService.getUserWithAuthrts(ssoId);
        if (user == null) {
            log.warn("[SSO] 사용자 없음 - ssoId: {} (DB 미등록)", ssoId);
            session.removeAttribute("SSO_ID");
            session.removeAttribute("SSO_REDIRECT_COUNT");
            return "redirect:/magicsso/sso_login_required.jsp?reason=not_registered";
        }

        LoginVO sessionUser = copyUserForSession(user);
        session.setAttribute("loginVO", sessionUser);
        securityUserService.updateUserSession(ssoId);
        session.removeAttribute("SSO_REDIRECT_COUNT");

        log.info("[SSO] 로그인 성공 - userId: {}, userName: {}", sessionUser.getUserId(), sessionUser.getUserNm());

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

        return "redirect:" + validateAndGetRedirectUrl(target);
    }

    /**
     * Open Redirect 공격 방지
     */
    private String validateAndGetRedirectUrl(String target) {
        if (target == null || target.trim().isEmpty()) {
            return defaultTarget;
        }
        target = target.replaceAll("<", "").replaceAll(">", "").replaceAll("\"", "").replaceAll("'", "");
        if (target.startsWith("http://") || target.startsWith("https://") || target.startsWith("//")) {
            log.warn("[SSO] 외부 URL 차단: {}", target);
            return defaultTarget;
        }
        if (!target.startsWith("/")) {
            return defaultTarget;
        }
        return target;
    }

    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;
    }
}
