package go.kr.project.carInspectionPenalty.registration.controller;

import egovframework.constant.MessageConstants;
import egovframework.constant.TilesConstants;
import egovframework.util.ApiResponseUtil;
import egovframework.util.SessionUtil;
import go.kr.project.carInspectionPenalty.registration.model.CarFfnlgTrgtVO;
import go.kr.project.carInspectionPenalty.registration.service.CarFfnlgTrgtService;
import go.kr.project.common.model.CmmnCodeSearchVO;
import go.kr.project.common.service.CommonCodeService;
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.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 자동차 과태료 대상 등록 Controller
 * 과태료 대상 목록 조회, TXT 파일 업로드 기능 제공
 */
@Controller
@RequestMapping("/carInspectionPenalty/registration")
@RequiredArgsConstructor
@Slf4j
@Tag(name = "자동차 과태료 대상 등록", description = "자동차 과태료 대상 등록 및 목록 조회 API")
public class CarFfnlgTrgtController {

    private final CarFfnlgTrgtService service;
    private final CommonCodeService commonCodeService;
    
    /**
     * 과태료 대상 목록 화면
     * @param model 모델
     * @return 목록 화면 경로
     */
    @GetMapping("/list.do")
    @Operation(summary = "과태료 대상 목록 화면", description = "과태료 대상 목록 조회 화면을 제공합니다.")
    public String list(Model model) {
        log.debug("과태료 대상 목록 화면 요청");
        
        // 업무 처리 상태 코드 조회 (공통코드)
        CmmnCodeSearchVO taskPrcsSttsCdSearchVO = CmmnCodeSearchVO.builder()
                .searchCdGroupId("TASK_PRCS_STTS_CD")
                .searchUseYn("Y")
                .sortColumn("SORT_ORDR")
                .sortAscending(true)
                .build();
        model.addAttribute("taskPrcsSttsCdList", commonCodeService.selectCodeDetailList(taskPrcsSttsCdSearchVO));
        
        return "carInspectionPenalty/registration/list" + TilesConstants.BASE;
    }
    
    /**
     * 과태료 대상 목록 조회 AJAX
     * @param paramVO 검색 조건
     * @return 목록 데이터
     */
    @PostMapping("/list.ajax")
    @Operation(summary = "과태료 대상 목록 조회", description = "과태료 대상 목록을 조회하고 JSON 형식으로 반환합니다.")
    public ResponseEntity<?> listAjax(@ModelAttribute CarFfnlgTrgtVO paramVO) {
        log.debug("과태료 대상 목록 조회 AJAX - 검색조건: {}", paramVO);
        
        // 1. 총 개수 조회
        int totalCount = service.selectListTotalCount(paramVO);
        
        // 2. totalCount 설정
        paramVO.setTotalCount(totalCount);
        
        // 3. 페이징 활성화
        paramVO.setPagingYn("Y");
        
        // 목록 조회
        List<CarFfnlgTrgtVO> list = service.selectList(paramVO);
        
        return ApiResponseUtil.successWithGrid(list, paramVO);
    }

    /**
     * 과태료 대상 목록 다운로드 (EUC-KR 텍스트)
     * 샘플 파일과 동일한 고정폭 포맷으로 생성하여 다운로드 제공합니다.
     * - 인코딩: EUC-KR (한글 2바이트)
     * - 헤더/구분선/컬럼 구성은 docs/샘플용-EUC-KR.txt와 동일
     */
    @GetMapping("/download.do")
    @Operation(summary = "과태료 대상 목록 다운로드", description = "EUC-KR 인코딩의 고정폭 텍스트로 목록을 샘플과 동일한 포맷으로 다운로드합니다.")
    public void download(
            @ModelAttribute CarFfnlgTrgtVO paramVO,
            HttpServletResponse response
    ) {
        try {

            // 페이징 없이 전체 조회를 위해 페이징 비활성화
            paramVO.setPagingYn("N");

            // 서비스에서 EUC-KR 텍스트 콘텐츠 생성
            byte[] fileBytes = service.generateEucKrDownloadBytes(paramVO);

            String fileName = URLEncoder.encode("유효기간경과_과태료부과대상_리스트.txt", "UTF-8");

            // 응답 헤더 설정 (텍스트 파일, EUC-KR 인코딩)
            response.setContentType("text/plain; charset=EUC-KR");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            response.setContentLength(fileBytes.length);

            // 바이트 스트림으로 전송 (본문은 EUC-KR 바이트)
            response.getOutputStream().write(fileBytes);
            response.getOutputStream().flush();
        } catch (Exception e) {
            log.error("목록 다운로드 중 오류", e);
            try {
                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                response.getWriter().write("다운로드 처리 중 오류가 발생했습니다: " + e.getMessage());
            } catch (Exception ignored) {

            }
        }
    }
    
    /**
     * 파일 업로드 팝업 화면
     * @return 팝업 화면
     */
    @GetMapping("/uploadPopup.do")
    @Operation(summary = "파일 업로드 팝업", description = "TXT 파일 업로드 팝업 화면을 제공합니다.")
    public ModelAndView uploadPopup() {
        log.debug("파일 업로드 팝업 화면 요청");
        
        ModelAndView mav = new ModelAndView("carInspectionPenalty/registration/uploadPopup" + TilesConstants.POPUP);
        
        return mav;
    }
    
    /**
     * TXT 파일 업로드 및 처리
     * 
     * 주의: 파일 단위로 업로드하므로 한 건이라도 실패하면 전체 롤백 처리됨
     * 
     * @param file 업로드된 TXT 파일
     * @return 처리 결과
     */
    @PostMapping("/upload.ajax")
    @Operation(summary = "TXT 파일 업로드", description = "TXT 파일을 업로드하고 파싱하여 DB에 저장합니다. 한 건이라도 실패 시 전체 롤백됩니다.")
    public ResponseEntity<?> upload(
            @Parameter(description = "TXT 파일") @RequestParam("file") MultipartFile file) {
        
        log.info("TXT 파일 업로드 요청 - 파일명: {}", file != null ? file.getOriginalFilename() : "null");
        
        try {
            // 세션에서 사용자 ID 가져오기
            String rgtr = SessionUtil.getUserId();
            if (rgtr == null || rgtr.isEmpty()) {
                return ApiResponseUtil.error("로그인 정보가 없습니다.");
            }
            
            // 파일 업로드 및 파싱 (한 건이라도 실패 시 전체 롤백)
            Map<String, Object> result = service.uploadAndParseTxtFile(file, rgtr);
            
            boolean success = (boolean) result.get("success");
            int successCount = (int) result.get("successCount");
            @SuppressWarnings("unchecked")
            List<String> errorMessages = (List<String>) result.get("errorMessages");
            
            if (success) {
                // 모든 데이터가 성공적으로 저장됨
                String message = String.format("파일 업로드가 완료되었습니다.\n\n성공: %d건", successCount);
                return ApiResponseUtil.success(result, message);
            } else {
                // 파일 검증 오류 (트랜잭션 시작 전 오류)
                StringBuilder message = new StringBuilder();
                if (!errorMessages.isEmpty()) {
                    for (String errorMsg : errorMessages) {
                        message.append(errorMsg).append("\n");
                    }
                } else {
                    message.append("파일 업로드 중 오류가 발생했습니다.");
                }
                return ApiResponseUtil.error(message.toString());
            }
            
        } catch (RuntimeException e) {
            // 데이터 처리 중 오류 발생 - 전체 롤백됨
            log.error("TXT 파일 업로드 중 오류 발생 - 전체 롤백", e);
            return ApiResponseUtil.error(e.getMessage());
        } catch (Exception e) {
            // 예상치 못한 오류
            log.error("TXT 파일 업로드 중 예상치 못한 오류 발생", e);
            return ApiResponseUtil.error("파일 업로드 중 오류가 발생했습니다: " + e.getMessage());
        }
    }
    
    /**
     * 과태료 대상 상세 조회
     * @param carFfnlgTrgtId 과태료 대상 ID
     * @return 상세 정보
     */
    @GetMapping("/selectOne.ajax")
    @Operation(summary = "과태료 대상 상세 조회", description = "과태료 대상 상세 정보를 조회합니다.")
    public ResponseEntity<?> selectOne(
            @Parameter(description = "과태료 대상 ID") @RequestParam String carFfnlgTrgtId) {
        
        log.debug("과태료 대상 상세 조회 - ID: {}", carFfnlgTrgtId);
        
        try {
            CarFfnlgTrgtVO vo = new CarFfnlgTrgtVO();
            vo.setCarFfnlgTrgtId(carFfnlgTrgtId);
            
            CarFfnlgTrgtVO result = service.selectOne(vo);
            
            if (result != null) {
                return ApiResponseUtil.success(result, "조회 성공");
            } else {
                return ApiResponseUtil.error("조회된 데이터가 없습니다.");
            }
            
        } catch (Exception e) {
            log.error("과태료 대상 상세 조회 중 오류 발생", e);
            return ApiResponseUtil.error("조회 중 오류가 발생했습니다: " + e.getMessage());
        }
    }
    
    /**
     * 과태료 대상 삭제 (논리삭제)
     * @param carFfnlgTrgtId 과태료 대상 ID
     * @return 삭제 결과
     */
    @PostMapping("/delete.ajax")
    @Operation(summary = "과태료 대상 삭제", description = "과태료 대상을 삭제(논리삭제)합니다.")
    public ResponseEntity<?> delete(
            @Parameter(description = "과태료 대상 ID") @RequestParam String carFfnlgTrgtId) {

        log.info("과태료 대상 삭제 요청 - ID: {}", carFfnlgTrgtId);

        try {
            String dltr = SessionUtil.getUserId();
            if (dltr == null || dltr.isEmpty()) {
                return ApiResponseUtil.error("로그인 정보가 없습니다.");
            }

            CarFfnlgTrgtVO vo = new CarFfnlgTrgtVO();
            vo.setCarFfnlgTrgtId(carFfnlgTrgtId);
            vo.setDltr(dltr);

            int result = service.delete(vo);

            if (result > 0) {
                return ApiResponseUtil.success(MessageConstants.Common.DELETE_SUCCESS);
            } else {
                return ApiResponseUtil.error(MessageConstants.Common.DELETE_ERROR);
            }

        } catch (Exception e) {
            log.error("과태료 대상 삭제 중 오류 발생", e);
            return ApiResponseUtil.error("삭제 중 오류가 발생했습니다: " + e.getMessage());
        }
    }

    /**
     * 선택된 목록에 대해 API 호출 및 기본정보/등록원부 비교
     * @param targetList 선택된 과태료 대상 목록
     * @return 비교 결과
     */
    @PostMapping("/compareWithApi.ajax")
    @ResponseBody
    @Operation(summary = "API 호출 및 데이터 비교", description = "선택된 목록에 대해 차량 API를 호출하고 기본정보 및 등록원부와 비교합니다.")
    public ResponseEntity<?> compareWithApi(@RequestBody List<Map<String, String>> targetList) {
        log.info("API 호출 및 비교 요청 - 선택된 데이터 건수: {}", targetList != null ? targetList.size() : 0);

        try {
            Map<String, Object> resultData = service.compareWithApi(targetList);

            int successCount = (int) resultData.get("successCount");
            int failCount = (int) resultData.get("failCount");
            String message = String.format("API 호출 및 비교 완료\n성공: %d건, 실패: %d건", successCount, failCount);

            return ApiResponseUtil.success(resultData, message);

        } catch (IllegalArgumentException e) {
            log.error("파라미터 검증 오류", e);
            return ApiResponseUtil.error(e.getMessage());
        } catch (Exception e) {
            log.error("API 호출 및 비교 중 오류 발생", e);
            return ApiResponseUtil.error("처리 중 오류가 발생했습니다: " + e.getMessage());
        }
    }

    /**
     * 검색조건 전체 목록에 대해 API 호출 및 기본정보/등록원부 비교 (페이징 없이)
     * @param searchParams 검색 조건 파라미터
     * @return 비교 결과
     */
    @PostMapping("/compareWithApiAll.ajax")
    @ResponseBody
    @Operation(summary = "검색조건 전체 API 호출 및 데이터 비교", description = "검색조건에 해당하는 전체 목록에 대해 차량 API를 호출하고 비교합니다.")
    public ResponseEntity<?> compareWithApiAll(@RequestBody CarFfnlgTrgtVO searchParams) {
        log.info("전체 API 호출 및 비교 요청 - 검색 조건: {}", searchParams);

        try {
            // 페이징 비활성화
            searchParams.setPagingYn("N");

            // 전체 목록 조회
            List<CarFfnlgTrgtVO> allData = service.selectList(searchParams);

            // 목록을 Map 형태로 변환
            List<Map<String, String>> targetList = allData.stream()
                    .map(vo -> {
                        Map<String, String> map = new HashMap<>();
                        map.put("carFfnlgTrgtId", vo.getCarFfnlgTrgtId());
                        map.put("vhclno", vo.getVhclno());
                        map.put("inspYmd", vo.getInspYmd());
                        map.put("ownrNm", vo.getOwnrNm());
                        map.put("carNm", vo.getCarNm());
                        return map;
                    })
                    .collect(java.util.stream.Collectors.toList());

            // API 호출 및 비교
            Map<String, Object> resultData = service.compareWithApi(targetList);

            int successCount = (int) resultData.get("successCount");
            int failCount = (int) resultData.get("failCount");
            String message = String.format("전체 API 호출 및 비교 완료\n대상: %d건, 성공: %d건, 실패: %d건",
                    allData.size(), successCount, failCount);

            return ApiResponseUtil.success(resultData, message);

        } catch (Exception e) {
            log.error("전체 API 호출 및 비교 중 오류 발생", e);
            return ApiResponseUtil.error("처리 중 오류가 발생했습니다: " + e.getMessage());
        }
    }

    /**
     * 과태료 대상 일괄 삭제
     * @param deleteIds 삭제할 과태료 대상 ID 목록
     * @return 삭제 결과
     */
    @PostMapping("/deleteBatch.ajax")
    @ResponseBody
    @Operation(summary = "과태료 대상 일괄 삭제", description = "선택된 과태료 대상 목록을 일괄 삭제합니다.")
    public ResponseEntity<?> deleteBatch(@RequestBody List<String> deleteIds) {
        log.info("일괄 삭제 요청 - 선택된 데이터 건수: {}", deleteIds != null ? deleteIds.size() : 0);

        try {
            if (deleteIds == null || deleteIds.isEmpty()) {
                return ApiResponseUtil.error("삭제할 데이터가 없습니다.");
            }

            int successCount = 0;
            int failCount = 0;

            for (String id : deleteIds) {
                try {
                    CarFfnlgTrgtVO vo = new CarFfnlgTrgtVO();
                    vo.setCarFfnlgTrgtId(id);
                    int result = service.delete(vo);

                    if (result > 0) {
                        successCount++;
                    } else {
                        failCount++;
                    }
                } catch (Exception e) {
                    log.error("삭제 실패 - ID: {}", id, e);
                    failCount++;
                }
            }

            String message = String.format("삭제 완료\n성공: %d건, 실패: %d건", successCount, failCount);

            Map<String, Object> resultData = new HashMap<>();
            resultData.put("successCount", successCount);
            resultData.put("failCount", failCount);

            return ApiResponseUtil.success(resultData, message);

        } catch (Exception e) {
            log.error("일괄 삭제 중 오류 발생", e);
            return ApiResponseUtil.error("삭제 중 오류가 발생했습니다: " + e.getMessage());
        }
    }
}
