package incheon.com.security.web;

import incheon.com.security.service.MaintenanceLoginService;
import incheon.com.security.vo.LoginVO;
import incheon.com.security.vo.UserAuthrtVO;
import incheon.com.security.vo.UserRoleVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.web.bind.annotation.*;

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

/**
 * 유지보수 전용 REST API Controller (개발/테스트 환경 전용, prod 차단)
 * - 시스템/역할 목록 조회
 * - 역할설정 모달: 전체 역할 조회, 역할 변경 (세션 업데이트)
 */
@Tag(name = "유지보수 API", description = "유지보수 전용 데이터 조회 및 역할 변경 API (개발 환경 전용)")
@Slf4j
@RestController
@RequestMapping("/api/v1/maintenance")
@RequiredArgsConstructor
public class MaintenanceLoginApiController {

    private final MaintenanceLoginService maintenanceLoginService;
    private final Environment environment;

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

    /**
     * 활성 시스템 목록 조회
     * GET /api/v1/maintenance/systems
     */
    @Operation(summary = "시스템 목록 조회", description = "활성화된 시스템 목록을 조회합니다")
    @GetMapping("/systems")
    public ResponseEntity<List<Map<String, Object>>> getSystems() {
        if (isProductionProfile()) {
            log.warn("[MAINTENANCE] 운영 환경에서 시스템 목록 조회 시도 차단");
            return ResponseEntity.ok(Collections.emptyList());
        }

        List<Map<String, Object>> systems = maintenanceLoginService.getActiveSystems();
        log.info("[MAINTENANCE] 시스템 목록 조회: {}개", systems.size());
        return ResponseEntity.ok(systems);
    }

    /**
     * 역할 타입 코드 목록 조회
     * GET /api/v1/maintenance/roleTypes
     */
    @Operation(summary = "역할 타입 코드 목록 조회", description = "역할 타입 공통코드 목록을 조회합니다")
    @GetMapping("/roleTypes")
    public ResponseEntity<List<Map<String, Object>>> getRoleTypes() {
        if (isProductionProfile()) {
            log.warn("[MAINTENANCE] 운영 환경에서 역할 타입 조회 시도 차단");
            return ResponseEntity.ok(Collections.emptyList());
        }

        List<Map<String, Object>> roleTypes = maintenanceLoginService.getRoleTypeCodes();
        log.info("[MAINTENANCE] 역할 타입 목록 조회: {}개", roleTypes.size());
        return ResponseEntity.ok(roleTypes);
    }

    /**
     * 시스템별 역할 목록 조회
     * GET /api/v1/maintenance/roles?sysCd=AGS
     */
    @Operation(summary = "시스템별 역할 목록 조회", description = "특정 시스템의 역할 목록을 조회합니다")
    @GetMapping("/roles")
    public ResponseEntity<List<Map<String, Object>>> getRolesBySysCd(
            @Parameter(description = "시스템 코드", required = true, example = "AGS")
            @RequestParam String sysCd) {

        if (isProductionProfile()) {
            log.warn("[MAINTENANCE] 운영 환경에서 역할 목록 조회 시도 차단");
            return ResponseEntity.ok(Collections.emptyList());
        }

        List<Map<String, Object>> roles = maintenanceLoginService.getRolesBySysCd(sysCd);
        log.info("[MAINTENANCE] 역할 목록 조회 - sysCd: {}, 결과: {}개", sysCd, roles.size());
        return ResponseEntity.ok(roles);
    }

    /**
     * 전체 역할 목록 조회 (역할설정 모달용)
     * 시스템별 그룹핑 + 현재 세션의 선택된 역할 코드 반환
     */
    @Operation(summary = "전체 역할 목록 조회", description = "시스템별 그룹핑된 역할 목록과 현재 세션 역할을 조회합니다")
    @GetMapping("/allRoles")
    public ResponseEntity<Map<String, Object>> getAllRoles(HttpServletRequest request) {
        if (isProductionProfile()) {
            return ResponseEntity.ok(Collections.emptyMap());
        }

        HttpSession session = request.getSession(false);
        if (session == null) {
            return ResponseEntity.status(401).build();
        }

        LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
        if (loginVO == null || !"M".equals(loginVO.getUserStcd())) {
            return ResponseEntity.status(403).build();
        }

        List<UserRoleVO> allRoles = maintenanceLoginService.getAllActiveRoles();

        List<String> currentRoleCds = new ArrayList<>();
        if (loginVO.getUserRoles() != null) {
            for (UserRoleVO role : loginVO.getUserRoles()) {
                currentRoleCds.add(role.getRoleCd());
            }
        }

        Map<String, List<Map<String, String>>> groupedRoles = new LinkedHashMap<>();
        for (UserRoleVO role : allRoles) {
            // 임시역할 제외
            if (role.getRoleCd() != null && role.getRoleCd().startsWith("ROLE_TMPR_")) {
                continue;
            }
            groupedRoles
                    .computeIfAbsent(role.getSysCd(), k -> new ArrayList<>())
                    .add(Map.of(
                            "roleCd", role.getRoleCd(),
                            "roleNm", role.getRoleNm() != null ? role.getRoleNm() : role.getRoleCd(),
                            "roleTypeCd", role.getRoleTypeCd() != null ? role.getRoleTypeCd() : ""
                    ));
        }

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("groupedRoles", groupedRoles);
        result.put("currentRoleCds", currentRoleCds);

        return ResponseEntity.ok(result);
    }

    /**
     * 역할 변경 - 선택된 역할로 세션의 역할/권한/시스템 재설정
     */
    @Operation(summary = "역할 변경", description = "선택된 역할로 세션의 역할/권한을 재설정합니다")
    @PostMapping("/updateRoles")
    public ResponseEntity<Map<String, Object>> updateRoles(
            @RequestBody Map<String, List<String>> body,
            HttpServletRequest request) {

        if (isProductionProfile()) {
            return ResponseEntity.ok(Map.of("success", false, "message", "운영 환경에서는 사용할 수 없습니다"));
        }

        HttpSession session = request.getSession(false);
        if (session == null) {
            return ResponseEntity.status(401).build();
        }

        LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
        if (loginVO == null || !"M".equals(loginVO.getUserStcd())) {
            return ResponseEntity.status(403).build();
        }

        List<String> selectedRoleCds = body.get("roleCds");
        if (selectedRoleCds == null || selectedRoleCds.isEmpty()) {
            return ResponseEntity.ok(Map.of("success", false, "message", "역할을 1개 이상 선택해주세요"));
        }

        try {
            // 전체 역할에서 선택된 것만 필터
            List<UserRoleVO> allRoles = maintenanceLoginService.getAllActiveRoles();
            Set<String> selectedSet = new HashSet<>(selectedRoleCds);
            List<UserRoleVO> filteredRoles = new ArrayList<>();
            for (UserRoleVO role : allRoles) {
                if (selectedSet.contains(role.getRoleCd())) {
                    filteredRoles.add(role);
                }
            }

            // 역할 기반 권한 재조회 → Spring Security Authority 구성
            List<UserAuthrtVO> authrts = maintenanceLoginService.getAuthrtsByRoleCds(selectedRoleCds);
            List<GrantedAuthority> authorities = new ArrayList<>();
            Set<String> authoritySet = new HashSet<>();
            for (UserAuthrtVO authrt : authrts) {
                String authority = authrt.toAuthority();
                if (authoritySet.add(authority)) {
                    authorities.add(new SimpleGrantedAuthority(authority));
                }
            }

            Set<String> sysCdSet = new LinkedHashSet<>();
            for (UserRoleVO role : filteredRoles) {
                sysCdSet.add(role.getSysCd());
            }
            List<String> activeSysCds = new ArrayList<>(sysCdSet);
            Collections.sort(activeSysCds);
            // 선택된 역할 기반으로 관리자 권한 동적 세팅
            boolean isSuperAdmin = filteredRoles.stream()
                    .anyMatch(r -> "ROLTYP001".equals(r.getRoleTypeCd()));
            List<String> adminSysCds = new ArrayList<>();
            for (UserRoleVO role : filteredRoles) {
                if ("ROLTYP002".equals(role.getRoleTypeCd()) && role.getSysCd() != null) {
                    if (!adminSysCds.contains(role.getSysCd())) {
                        adminSysCds.add(role.getSysCd());
                    }
                }
            }
            Collections.sort(adminSysCds);

            loginVO.setUserRoles(filteredRoles);
            loginVO.setUserAuthrts(authrts);
            loginVO.setAuthorities(authorities);
            loginVO.setActiveSysCds(activeSysCds);
            loginVO.setSuperAdmin(isSuperAdmin);
            loginVO.setAdminSysCds(adminSysCds);
            session.setAttribute("loginVO", loginVO);

            long sysCnt = authrts.stream().filter(a -> "SYS".equals(a.getScope())).count();
            long menuCnt = authrts.stream().filter(a -> "MENU".equals(a.getScope())).count();
            log.info("[MAINTENANCE] 역할 변경 - roles: {}개, authrts: {}개 (SYS:{}, MENU:{}), systems: {}",
                    filteredRoles.size(), authrts.size(), sysCnt, menuCnt, activeSysCds);

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "roleCount", filteredRoles.size(),
                    "authrtCount", authrts.size(),
                    "systemCount", activeSysCds.size()
            ));

        } catch (Exception e) {
            log.error("[MAINTENANCE] 역할 변경 중 오류", e);
            return ResponseEntity.ok(Map.of("success", false, "message", "역할 변경 처리 중 오류가 발생했습니다"));
        }
    }

}
