package incheon.ags.uis.code.web;

import incheon.ags.uis.code.service.CodeDetailService;
import incheon.ags.uis.code.vo.CodeDetailVO;
import incheon.com.security.vo.LoginVO;
import lombok.extern.slf4j.Slf4j;

import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
import incheon.ags.uis.code.service.CodeGroupService;
import incheon.ags.uis.code.vo.CodeGroupVO;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;

@Slf4j
@Controller
@RequestMapping("/ags/uis/code")
public class CodeGroupController {

    private final CodeGroupService codeGroupService;
    private final CodeDetailService codeDetailService;

    public CodeGroupController(CodeGroupService codeGroupService,
                               CodeDetailService codeDetailService) {
        this.codeGroupService = codeGroupService;
        this.codeDetailService = codeDetailService;
    }

    /**
     * 코드 그룹 목록
     *  - GET /ags/uis/code/groupList.do
     */
    @GetMapping("/groupList.do")
    public String groupList(@ModelAttribute("searchVO") CodeGroupVO searchVO,
                            @RequestParam(value = "useYn", required = false) String useYn,
                            @RequestParam(value = "searchKeyword", required = false) String searchKeyword,
                            @RequestParam(value = "page", required = false, defaultValue = "1") int page,
                            HttpServletRequest request,
                            Model model) {

        // 검색조건 매핑 (ComDefaultVO)
        searchVO.setSearchUseYn(useYn);
        searchVO.setSearchKeyword(searchKeyword);

        // 페이지 번호 설정
        searchVO.setPageIndex(page);

        // eGov 페이징 세팅
        PaginationInfo paginationInfo = new PaginationInfo();
        paginationInfo.setCurrentPageNo(searchVO.getPageIndex());
        paginationInfo.setRecordCountPerPage(searchVO.getRecordCountPerPage()); // 기본 10
        paginationInfo.setPageSize(searchVO.getPageSize());                     // 기본 10

        searchVO.setFirstIndex(paginationInfo.getFirstRecordIndex());
        searchVO.setLastIndex(paginationInfo.getLastRecordIndex());
        searchVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());

        // 총 건수
        int totalCount = codeGroupService.selectCodeGroupListCount(searchVO);
        paginationInfo.setTotalRecordCount(totalCount);

        // 목록 조회
        List<CodeGroupVO> groupCdList = codeGroupService.selectCodeGroupList(searchVO);

        // 모델
        model.addAttribute("groupCdList", groupCdList);
        model.addAttribute("paginationInfo", paginationInfo);
        model.addAttribute("totalCount", totalCount);

        // 검색값 다시 내려주기 (JSP에서 ${useYn}, ${searchKeyword})
        model.addAttribute("useYn", useYn);
        model.addAttribute("searchKeyword", searchKeyword);

        return "ags/uis/code/codeGroupList";
    }

    /**
     * 그룹 등록 페이지
     */
    @GetMapping("/groupRegist.do")
    public String groupRegistPage() {
        return "ags/uis/code/codeGroupRegist";
    }

    /**
     * 그룹 등록 처리
     */
    @PostMapping("/groupRegist.do")
    public String groupRegistSubmit(@ModelAttribute("vo") CodeGroupVO vo,
                                    HttpSession session,
                                    RedirectAttributes redirectAttributes) {

        String loginId = resolveLoginId(session);
        vo.setLOGIN_USER_ID(loginId);

        try {
            codeGroupService.insertCodeGroup(vo);
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 등록되었습니다.");
        } catch (DataIntegrityViolationException e) {
            log.warn("그룹코드 등록 실패 - 제약 조건 위반: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "이미 존재하는 그룹코드이거나 제약 조건을 위반했습니다.");
        } catch (IllegalArgumentException e) {
            log.warn("그룹코드 등록 실패 - 잘못된 파라미터: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "입력값이 올바르지 않습니다: " + e.getMessage());
        } catch (Exception e) {
            log.error("그룹코드 등록 중 예상치 못한 오류 발생: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "그룹코드 등록 중 오류가 발생했습니다.");
        }

        return "redirect:/ags/uis/code/groupList.do";
    }

    /**
     * 그룹 상세
     */
    @GetMapping("/groupDetail.do")
    public String groupDetail(@RequestParam("groupCd") String groupCd,
                              Model model,
                              RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeGroupVO group = codeGroupService.selectCodeGroup(groupCd);
        if (group == null) {
            redirectAttributes.addFlashAttribute("msg", "해당 그룹코드를 찾을 수 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        model.addAttribute("group", group);

        // 상세코드 목록
        List<CodeDetailVO> cdList = codeDetailService.selectCodeDetailListByGroupCd(groupCd);
        model.addAttribute("cdList", cdList);

        return "ags/uis/code/codeGroupDetail";
    }

    /**
     * 그룹 수정 페이지
     */
    @GetMapping("/groupModify.do")
    public String groupModifyPage(@RequestParam("groupCd") String groupCd,
                                  Model model,
                                  RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeGroupVO group = codeGroupService.selectCodeGroup(groupCd);
        if (group == null) {
            redirectAttributes.addFlashAttribute("msg", "해당 그룹코드를 찾을 수 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        model.addAttribute("group", group);
        return "ags/uis/code/codeGroupModify";
    }

    /**
     * 그룹 수정 처리
     */
    @PostMapping("/groupModify.do")
    public String groupModifySubmit(@ModelAttribute("vo") CodeGroupVO vo,
                                    HttpSession session,
                                    RedirectAttributes redirectAttributes) {

        String loginId = resolveLoginId(session);
        vo.setLOGIN_USER_ID(loginId);

        if (vo.getGroupCd() == null || vo.getGroupCd().isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        try {
            codeGroupService.updateCodeGroup(vo);
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 수정되었습니다.");
        } catch (DataIntegrityViolationException e) {
            log.warn("그룹코드 수정 실패 - 제약 조건 위반: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "그룹코드 수정 중 제약 조건을 위반했습니다.");
        } catch (IllegalArgumentException e) {
            log.warn("그룹코드 수정 실패 - 잘못된 파라미터: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "입력값이 올바르지 않습니다: " + e.getMessage());
        } catch (Exception e) {
            log.error("그룹코드 수정 중 예상치 못한 오류 발생: groupCd={}", vo.getGroupCd(), e);
            redirectAttributes.addFlashAttribute("msg", "그룹코드 수정 중 오류가 발생했습니다.");
        }

        redirectAttributes.addAttribute("groupCd", vo.getGroupCd());
        return "redirect:/ags/uis/code/groupDetail.do";

    }

    // ───────────────── 상세코드 등록/수정/삭제 ─────────────────

    @GetMapping("/cdRegist.do")
    public String cdRegist(@RequestParam("groupCd") String groupCd,
                           Model model,
                           RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeGroupVO group = codeGroupService.selectCodeGroup(groupCd);
        if (group == null) {
            redirectAttributes.addFlashAttribute("msg", "해당 그룹코드를 찾을 수 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeDetailVO detail = new CodeDetailVO();
        detail.setGroupCd(groupCd);
        detail.setUseYn("Y");

        model.addAttribute("group", group);
        model.addAttribute("detail", detail);
        model.addAttribute("mode", "create");

        return "ags/uis/code/codeDetailRegist";
    }

    @PostMapping("/cdRegist.do")
    public String cdRegistSubmit(CodeDetailVO detail,
                                 HttpSession session,
                                 RedirectAttributes redirectAttributes) {

        String groupCd = detail.getGroupCd();

        if (groupCd == null || groupCd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "그룹코드가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }
        if (detail.getCd() == null || detail.getCd().isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "상세코드를 입력하세요.");
            redirectAttributes.addAttribute("groupCd", groupCd);
            return "redirect:/ags/uis/code/cdRegist.do";
        }

        String loginId = resolveLoginId(session);
        detail.setLOGIN_USER_ID(loginId);
        detail.setFrstRegId(loginId);
        detail.setLastMdfcnId(loginId);

        try {
            codeDetailService.insertCodeDetail(detail);
            redirectAttributes.addFlashAttribute("msg", "상세코드가 등록되었습니다.");
        } catch (DataIntegrityViolationException e) {
            log.warn("상세코드 등록 실패 - 제약 조건 위반: groupCd={}, cd={}", groupCd, detail.getCd(), e);
            redirectAttributes.addFlashAttribute("msg", "이미 존재하는 상세코드이거나 제약 조건을 위반했습니다.");
            redirectAttributes.addAttribute("groupCd", groupCd);
            return "redirect:/ags/uis/code/cdRegist.do";
        } catch (IllegalArgumentException e) {
            log.warn("상세코드 등록 실패 - 잘못된 파라미터: groupCd={}, cd={}", groupCd, detail.getCd(), e);
            redirectAttributes.addFlashAttribute("msg", "입력값이 올바르지 않습니다: " + e.getMessage());
            redirectAttributes.addAttribute("groupCd", groupCd);
            return "redirect:/ags/uis/code/cdRegist.do";
        } catch (Exception e) {
            log.error("상세코드 등록 중 예상치 못한 오류 발생: groupCd={}, cd={}", groupCd, detail.getCd(), e);
            redirectAttributes.addFlashAttribute("msg", "상세코드 등록 중 오류가 발생했습니다.");
            redirectAttributes.addAttribute("groupCd", groupCd);
            return "redirect:/ags/uis/code/cdRegist.do";
        }

        redirectAttributes.addAttribute("groupCd", groupCd);
        return "redirect:/ags/uis/code/groupDetail.do";
    }


    @GetMapping("/cdModify.do")
    public String cdModify(@RequestParam("groupCd") String groupCd,
                           @RequestParam("cd") String cd,
                           Model model,
                           RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank() || cd == null || cd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "코드 정보가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeGroupVO group = codeGroupService.selectCodeGroup(groupCd);
        if (group == null) {
            redirectAttributes.addFlashAttribute("msg", "해당 그룹코드를 찾을 수 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        CodeDetailVO detail = codeDetailService.selectCodeDetail(groupCd, cd);
        if (detail == null) {
            redirectAttributes.addFlashAttribute("msg", "해당 상세코드를 찾을 수 없습니다.");
            return "redirect:/ags/uis/code/groupDetail.do?groupCd=" + groupCd;
        }

        model.addAttribute("group", group);
        model.addAttribute("detail", detail);
        model.addAttribute("mode", "edit");

        return "ags/uis/code/codeDetailModify";
    }

    @PostMapping("/cdModify.do")
    public String cdModifySubmit(@RequestParam("groupCd") String groupCd,
                                 @RequestParam("cd") String cd,
                                 CodeDetailVO detail,
                                 HttpSession session,
                                 RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank() || cd == null || cd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "코드 정보가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        detail.setGroupCd(groupCd);
        detail.setCd(cd);

        String loginId = resolveLoginId(session);
        detail.setLOGIN_USER_ID(loginId);
        detail.setLastMdfcnId(loginId);

        try {
            codeDetailService.updateCodeDetail(detail);
            redirectAttributes.addFlashAttribute("msg", "상세코드가 수정되었습니다.");
        } catch (DataIntegrityViolationException e) {
            log.warn("상세코드 수정 실패 - 제약 조건 위반: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "상세코드 수정 중 제약 조건을 위반했습니다.");
            redirectAttributes.addAttribute("groupCd", groupCd);
            redirectAttributes.addAttribute("cd", cd);
            return "redirect:/ags/uis/code/cdModify.do";
        } catch (IllegalArgumentException e) {
            log.warn("상세코드 수정 실패 - 잘못된 파라미터: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "입력값이 올바르지 않습니다: " + e.getMessage());
            redirectAttributes.addAttribute("groupCd", groupCd);
            redirectAttributes.addAttribute("cd", cd);
            return "redirect:/ags/uis/code/cdModify.do";
        } catch (Exception e) {
            log.error("상세코드 수정 중 예상치 못한 오류 발생: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "상세코드 수정 중 오류가 발생했습니다.");
            redirectAttributes.addAttribute("groupCd", groupCd);
            redirectAttributes.addAttribute("cd", cd);
            return "redirect:/ags/uis/code/cdModify.do";
        }

        redirectAttributes.addAttribute("groupCd", groupCd);
        return "redirect:/ags/uis/code/groupDetail.do";
    }


    @PostMapping("/cdDelete.do")
    public String cdDelete(@RequestParam("groupCd") String groupCd,
                           @RequestParam("cd") String cd,
                           RedirectAttributes redirectAttributes) {

        if (groupCd == null || groupCd.isBlank() || cd == null || cd.isBlank()) {
            redirectAttributes.addFlashAttribute("msg", "삭제할 코드 정보가 없습니다.");
            return "redirect:/ags/uis/code/groupList.do";
        }

        try {
            codeDetailService.deleteCodeDetail(groupCd, cd);
            redirectAttributes.addFlashAttribute("msg", "상세코드가 삭제되었습니다.");
        } catch (DataIntegrityViolationException e) {
            log.warn("상세코드 삭제 실패 - 참조 데이터 존재: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "해당 상세코드를 사용하는 데이터가 존재하여 삭제할 수 없습니다.");
        } catch (IllegalArgumentException e) {
            log.warn("상세코드 삭제 실패 - 잘못된 파라미터: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "입력값이 올바르지 않습니다: " + e.getMessage());
        } catch (Exception e) {
            log.error("상세코드 삭제 중 예상치 못한 오류 발생: groupCd={}, cd={}", groupCd, cd, e);
            redirectAttributes.addFlashAttribute("msg", "상세코드 삭제 중 오류가 발생했습니다.");
        }

        redirectAttributes.addAttribute("groupCd", groupCd);
        return "redirect:/ags/uis/code/groupDetail.do";
    }

    // ───────────────── 내부 공통 메서드 ─────────────────

    private String resolveLoginId(HttpSession session) {
        String loginId = "ADMIN";
        Object loginVO = session != null ? session.getAttribute("loginVO") : null;
        if (loginVO != null) {
            loginId = ((LoginVO) loginVO).getUserId();
        }
        return loginId;
    }
}
