package incheon.cmm.g3d.DbMngList.web;

import incheon.cmm.g3d.DbMngList.service.G3DDbMngService;
import incheon.cmm.g3d.DbMngList.vo.G3DDbMngVO;
import incheon.com.cmm.api.DefaultApiResponse;
import incheon.com.security.vo.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@Slf4j
@Controller
@RequestMapping("/cmm/g3d/dbMng")
public class G3DDbMngController {

    private final G3DDbMngService dbMngService;

    // 허용되지 않는 특수문자 패턴: < > ' " / \
    private static final Pattern DANGEROUS_CHARS = Pattern.compile("[<>'\"/\\\\]");

    public G3DDbMngController(G3DDbMngService dbMngService) {
        this.dbMngService = dbMngService;
    }

    @GetMapping("/dbMngList.do")
    public String listOriginal(Model model,
                               @RequestParam(value = "page", defaultValue = "1") int page,
                               @RequestParam(required = false) String categoryFilter,
                               @RequestParam(value = "searchKeyword", required = false) String searchKeyword,
                               @RequestParam(value = "searchType", required = false) String searchType,
                               @RequestParam(value = "dgtlPairGroupCd", required = false) String dgtlPairGroupCd,
                               @ModelAttribute G3DDbMngVO vo) {

        // 페이지 인덱스 설정
        vo.setPageIndex(page);

        // PaginationInfo 객체 생성 (전자정부 표준)
        PaginationInfo paginationInfo = new PaginationInfo();
        paginationInfo.setCurrentPageNo(page);
        paginationInfo.setRecordCountPerPage(vo.getRecordCountPerPage());
        paginationInfo.setPageSize(vo.getPageSize());

        // 페이징 인덱스 설정
        vo.setFirstIndex(paginationInfo.getFirstRecordIndex());
        vo.setLastIndex(paginationInfo.getLastRecordIndex());
        vo.setRecordCountPerPage(paginationInfo.getRecordCountPerPage());

        // 전체 개수 조회
        String srvcNum = "1";
        int totalCount = dbMngService.getTotalCount(searchKeyword, categoryFilter, searchType, srvcNum, dgtlPairGroupCd);
        paginationInfo.setTotalRecordCount(totalCount);

        // 목록 조회
        List<G3DDbMngVO> list = dbMngService.getList(searchKeyword, categoryFilter, searchType, page, vo.getRecordCountPerPage(), srvcNum, dgtlPairGroupCd);

        // Model에 데이터 추가
        model.addAttribute("list", list);
        model.addAttribute("totalCount", totalCount);
        model.addAttribute("paginationInfo", paginationInfo);
        model.addAttribute("categoryFilter", categoryFilter);
        model.addAttribute("categoryFilter", dgtlPairGroupCd);
        model.addAttribute("searchKeyword", searchKeyword);
        model.addAttribute("searchType", searchType);
        model.addAttribute("searchVO", vo);

        return "cmm/g3d/DbMng/DbMngList";
    }

    @GetMapping("/create.do")
    public String showCreateForm(Model model) {
        model.addAttribute("poi", new G3DDbMngVO());
        return "cmm/g3d/DbMng/DbMngCreate";
    }
    @PostMapping("/create")
    public String create(@Valid @ModelAttribute("poi") G3DDbMngVO poi,
                         BindingResult bindingResult,
                         HttpSession session,
                         RedirectAttributes redirectAttributes,
                         Model model) {

        // 특수문자 유효성 검사
        if (!validateSpecialCharacters(poi, bindingResult)) {
            model.addAttribute("message", "입력값에 허용되지 않은 특수문자가 포함되어 있습니다.");
            model.addAttribute("messageType", "error");
            return "cmm/g3d/DbMng/DbMngCreate";
        }

        if (bindingResult.hasErrors()) {
            model.addAttribute("message", "필수 입력 항목을 확인해주세요.");
            model.addAttribute("messageType", "error");
            return "cmm/g3d/DbMng/DbMngCreate";
        }

        try {
            // JSON 디코딩
            if (poi.getDgtlPairMdlTrsfOption() != null && !poi.getDgtlPairMdlTrsfOption().isEmpty()) {
                String decoded = org.apache.commons.text.StringEscapeUtils.unescapeHtml4(
                    poi.getDgtlPairMdlTrsfOption()
                );
                poi.setDgtlPairMdlTrsfOption(decoded);
            }

            // 세션 정보 설정
            LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
            if (loginVO == null) {
                loginVO = new LoginVO();
                loginVO.setUserId("admin");
                loginVO.setUserNm("관리자");
            }

            poi.setSrvcSeCd("1");
            poi.setFrstRegId(loginVO.getUserId());
            poi.setLastMdfcnId(loginVO.getUserId());
            
            if (poi.getDgtlPairMdlTrsfJobStts() == null || poi.getDgtlPairMdlTrsfJobStts().isEmpty()) {
                poi.setDgtlPairMdlTrsfJobStts("0");
            }

            //  Service 호출 (트랜잭션 처리)
            dbMngService.create(poi);

            //  성공 시
            redirectAttributes.addFlashAttribute("message", "원본 데이터가 등록되었습니다.");
            redirectAttributes.addFlashAttribute("messageType", "success");
            
            log.info("원본 데이터 등록 성공: {}", poi.getDgtlPairMdlId());
            return "redirect:/cmm/g3d/dbMng/dbMngList.do";
            
        } catch (RuntimeException e) {
            log.error("원본 데이터 등록 실패", e);

            String errorMsg = e.getMessage();
            String userMessage = getUserFriendlyErrorMessage(errorMsg);
            
            model.addAttribute("message", userMessage);
            model.addAttribute("messageType", "error");
            model.addAttribute("poi", poi);
            
            return "cmm/g3d/DbMng/DbMngCreate";
        }
    }

    private String getUserFriendlyErrorMessage(String errorMsg) {
        if (errorMsg == null) {
            return "알 수 없는 오류가 발생했습니다. 관리자에게 문의하세요.";
        }
        
        if (errorMsg.contains("API 호출 실패") || errorMsg.contains("ID를 받지 못했습니다")) {
            return "GIS 웹서버 API 연동에 실패했습니다.";
        }
        
        if (errorMsg.contains("DB 등록 실패")) {
            return "데이터베이스 저장에 실패했습니다. 관리자에게 문의하세요.";
        }
        
        if (errorMsg.contains("네트워크") || errorMsg.contains("timeout")) {
            return "네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.";
        }
        
        return "원본 데이터 등록에 실패했습니다: " + errorMsg;
    }
    @GetMapping("/edit.do")
    public String editForm(@RequestParam Integer dgtlPairMdlId,
                           @RequestParam String srvcSeCd,
                           Model model) {

        G3DDbMngVO poi = dbMngService.getById(dgtlPairMdlId, srvcSeCd);

        if (poi == null) {
            log.warn("존재하지 않는 모델 - ID: {}, srvcSeCd: {}", dgtlPairMdlId, srvcSeCd);
            return "redirect:/cmm/g3d/dbMng/dbMngList.do";
        }

        model.addAttribute("poi", poi);
        return "cmm/g3d/DbMng/DbMngEdit";
    }

    @PostMapping("/edit")
    public String edit(@RequestParam Integer dgtlPairMdlId,
                       @RequestParam String srvcSeCd,
                       @Valid @ModelAttribute("poi") G3DDbMngVO poi,
                       BindingResult bindingResult,
                       HttpSession session,
                       RedirectAttributes redirectAttributes,
                       Model model) {

        // 특수문자 유효성 검사
        if (!validateSpecialCharacters(poi, bindingResult)) {
            model.addAttribute("message", "입력값에 허용되지 않은 특수문자가 포함되어 있습니다.");
            model.addAttribute("messageType", "error");
            model.addAttribute("poi", poi);
            return "cmm/g3d/DbMng/DbMngEdit";
        }

        if (bindingResult.hasErrors()) {
            model.addAttribute("message", "필수 입력 항목을 확인해주세요.");
            model.addAttribute("messageType", "error");
            return "cmm/g3d/DbMng/DbMngEdit";
        }

        try {
            LoginVO loginVO = (LoginVO) session.getAttribute("loginVO");
            if (loginVO == null) {
                log.warn("로그인되지 않은 사용자의 수정 시도");
                loginVO = new LoginVO();
                loginVO.setUserNm("관리자");
                loginVO.setUserId("admin");
            }

            G3DDbMngVO existingPoi = dbMngService.getById(dgtlPairMdlId, srvcSeCd);

            if (existingPoi == null) {
                log.warn("존재하지 않는 모델 - ID: {}, srvcSeCd: {}", dgtlPairMdlId, srvcSeCd);
                model.addAttribute("message", "존재하지 않는 데이터입니다.");
                model.addAttribute("messageType", "error");
                return "cmm/g3d/DbMng/DbMngEdit";
            }

            poi.setDgtlPairMdlId(dgtlPairMdlId);
            poi.setSrvcSeCd(srvcSeCd);
            poi.setLastMdfcnId(loginVO.getUserId());

            dbMngService.update(poi);
            
            redirectAttributes.addFlashAttribute("message", "원본 데이터가 수정되었습니다.");
            redirectAttributes.addFlashAttribute("messageType", "success");
            
            log.info("원본 데이터 수정 성공: {}", dgtlPairMdlId);
            
            return "redirect:/cmm/g3d/dbMng/dbMngList.do";
            
        } catch (Exception e) {
            log.error("원본 데이터 수정 실패", e);
            
            String errorMsg = e.getMessage();
            String userMessage;
            
            if (errorMsg != null && errorMsg.contains("API")) {
                userMessage = "외부 API 연동에 실패했습니다: " + errorMsg;
            } else {
                userMessage = "원본 데이터 수정에 실패했습니다: " + errorMsg;
            }
            
            model.addAttribute("message", userMessage);
            model.addAttribute("messageType", "error");
            model.addAttribute("poi", poi);
            
            return "cmm/g3d/DbMng/DbMngEdit";
        }
    }

    @PostMapping("/delete")
    public String delete(@RequestParam Integer dgtlPairMdlId,
                         @RequestParam String srvcSeCd,
                         RedirectAttributes redirectAttributes) {
        try {
            log.info("원본 데이터 삭제 요청 - ID: {}, srvcSeCd: {}", dgtlPairMdlId, srvcSeCd);
            dbMngService.delete(dgtlPairMdlId, srvcSeCd);
            
            redirectAttributes.addFlashAttribute("message", "원본 데이터가 삭제되었습니다.");
            redirectAttributes.addFlashAttribute("messageType", "success");

            log.info("원본 데이터 삭제 성공: {}", dgtlPairMdlId);
        } catch (Exception e) {
            log.error("원본 데이터 삭제 실패 - ID: {}, srvcSeCd: {}", dgtlPairMdlId, srvcSeCd, e);
            
            String errorMsg = e.getMessage();
            String userMessage;
            
            if (errorMsg != null && errorMsg.contains("API")) {
                userMessage = "외부 API 삭제 요청에 실패했습니다.";
            } else {
                userMessage = "원본 데이터 삭제에 실패했습니다.";
            }
            
            redirectAttributes.addFlashAttribute("message", userMessage);
            redirectAttributes.addFlashAttribute("messageType", "error");
        }
        
        return "redirect:/cmm/g3d/dbMng/dbMngList.do";
    }

    @GetMapping(value = "/api/v1/dbMng", produces = "application/json")
    @ResponseBody
    public ResponseEntity<DefaultApiResponse<List<G3DDbMngVO>>> pois() throws IOException {
        return ResponseEntity.ok(DefaultApiResponse.success(dbMngService.getList()));
    }

    /**
     * 특수문자 유효성 검사
     * dgtlPairMdlSrvcNm과 dgtlPairMdlOrgnlPath는 경로/URL이므로 제외
     */
    private boolean validateSpecialCharacters(G3DDbMngVO poi, BindingResult bindingResult) {
        boolean isValid = true;

        if (poi.getDgtlPairMdlNm() != null && DANGEROUS_CHARS.matcher(poi.getDgtlPairMdlNm()).find()) {
            bindingResult.rejectValue("dgtlPairMdlNm",
                    "error.specialChar",
                    "데이터 이름에 허용되지 않은 특수문자가 포함되어 있습니다.");
            log.warn("데이터 이름에 허용되지 않은 특수문자 포함: {}", poi.getDgtlPairMdlNm());
            isValid = false;
        }

        if (poi.getDgtlPairMdlExpln() != null && DANGEROUS_CHARS.matcher(poi.getDgtlPairMdlExpln()).find()) {
            bindingResult.rejectValue("dgtlPairMdlExpln",
                    "error.specialChar",
                    "데이터 설명에 허용되지 않은 특수문자가 포함되어 있습니다.");
            log.warn("데이터 설명에 허용되지 않은 특수문자 포함");
            isValid = false;
        }

        return isValid;
    }
    @GetMapping("/api/v1/checkPath")
    @ResponseBody
    public Map<String, Object> checkPath(@RequestParam String path) {
        try {
            return dbMngService.checkStoragePath(path);
        } catch (Exception e) {
            log.error("경로 확인 중 예외 발생", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("statusCode", 500);
            result.put("message", "경로 확인 중 오류가 발생했습니다: " + e.getMessage());
            return result;
        }
    }
}