package incheon.ags.ias.srvy.publicSrvy.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import incheon.ags.ias.srvy.srvy.service.SrvyService;
import incheon.ags.ias.srvy.srvy.vo.SrvyVO;
import incheon.ags.ias.srvy.srvyRspdnt.service.SrvyRspdntService;
import incheon.ags.ias.srvy.srvyRspdnt.vo.SrvyRspdntVO;
import incheon.ags.ias.srvy.srvyRspns.service.SrvyRspnsService;
import incheon.ags.ias.srvy.srvyRspns.vo.SrvyRspnsVO;
import incheon.com.cmm.context.RequestContext;
import incheon.com.security.vo.LoginVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Controller
@RequestMapping("/ags/ias/publicSrvy")
@RequiredArgsConstructor
@Slf4j
public class SrvyPublicController {

    private final SrvyRspnsService srvyRspnsService;
    private final SrvyService srvyService;
    private final SrvyRspdntService srvyRspdntService;
    @Autowired private ObjectMapper objectMapper;

    private static final String VIEW_PREFIX = "/ags/ias/srvy/publicSrvy/";
    private static final String BASE_PATH = "/ags/ias/publicSrvy";

    @GetMapping("/start")
    public String startSrvy(@RequestParam(required = false) String srvySn,
                           HttpServletRequest request,
                           ModelMap model) {
        try {
            if (srvySn == null || srvySn.isEmpty()) {
                model.addAttribute("errorMessage", "설문조사 번호가 없습니다.");
                return VIEW_PREFIX + "error";
            }

            SrvyVO srvyVO = new SrvyVO();
            srvyVO.setSrvySn(Integer.parseInt(srvySn));
            SrvyVO srvyInfo = srvyService.selectSrvyDetail(srvyVO);

            if (srvyInfo == null) {
                model.addAttribute("errorMessage", "존재하지 않는 설문입니다.");
                return VIEW_PREFIX + "error";
            }

            // 내부 설문(SRVYTRGTTY002)만 허용
            if (!"SRVYTRGTTY002".equals(srvyInfo.getTrgtType())) {
                model.addAttribute("errorMessage", "잘못된 접근경로입니다.");
                return VIEW_PREFIX + "error";
            }

            // 설문조사 상태 체크 - 종료일이 지났는지 확인
            if (isSurveyExpired(srvyInfo.getSrvyEndYmd())) {
                model.addAttribute("errorMessage", "이 설문조사는 종료되었습니다.");
                return VIEW_PREFIX + "error";
            }

            // 내부 직원 대상 설문조사 로그인 체크
            String userId = getCurrentUserId(request);
            if ("unknown".equals(userId)) {
                model.addAttribute("errorMessage", "로그인이 필요합니다. 내부 직원은 로그인 후 설문조사에 참여해주세요.");
                return VIEW_PREFIX + "error";
            }

            model.addAttribute("srvyInfo", srvyInfo);
            model.addAttribute("basePath", BASE_PATH);

        } catch (Exception e) {
            log.error("설문조사 시작 페이지 로딩 중 오류 발생", e);
            model.addAttribute("errorMessage", "설문조사를 불러오는 중 오류가 발생했습니다.");
            return VIEW_PREFIX + "error";
        }

        return VIEW_PREFIX + "start";
    }

    @GetMapping("/participate")
    public String participateSrvy(@RequestParam(required = false) String srvySn,
                                    @RequestParam(required = false) String participantId,
                                    HttpServletRequest request,
                                    ModelMap model) {
        try {
            if (srvySn == null || srvySn.isEmpty()) {
                model.addAttribute("errorMessage", "설문조사 번호가 없습니다.");
                return VIEW_PREFIX + "error";
            }

            SrvyVO srvyVO = new SrvyVO();
            srvyVO.setSrvySn(Integer.parseInt(srvySn));
            SrvyVO srvyInfo = srvyService.selectSrvyDetail(srvyVO);

            if (srvyInfo == null) {
                model.addAttribute("errorMessage", "존재하지 않는 설문입니다.");
                return VIEW_PREFIX + "error";
            }

            // 내부 설문(SRVYTRGTTY002)만 허용
            if (!"SRVYTRGTTY002".equals(srvyInfo.getTrgtType())) {
                model.addAttribute("errorMessage", "잘못된 접근경로입니다.");
                return VIEW_PREFIX + "error";
            }

            // 설문조사 상태 체크 - 종료일이 지났는지 확인
            if (isSurveyExpired(srvyInfo.getSrvyEndYmd())) {
                model.addAttribute("errorMessage", "이 설문조사는 종료되었습니다.");
                return VIEW_PREFIX + "error";
            }

            // 내부 직원 대상 설문조사 로그인 체크
            String userId = getCurrentUserId(request);
            if ("unknown".equals(userId)) {
                model.addAttribute("errorMessage", "로그인이 필요합니다. 내부 직원은 로그인 후 설문조사에 참여해주세요.");
                return VIEW_PREFIX + "error";
            }

            // 설문조사 문항 목록 조회
            List<Map<String, Object>> questionList = srvyService.selectSrvyQitemListBySrvySn(Integer.parseInt(srvySn));
            if (questionList == null || questionList.isEmpty()) {
                model.addAttribute("errorMessage", "설문 문항이 없습니다.");
                return VIEW_PREFIX + "error";
            }

            // 설문조사 선택지 목록 조회
            Map<String, Object> searchParams = new HashMap<>();
            searchParams.put("srvySn", Integer.parseInt(srvySn));
            List<Map<String, Object>> itemList = srvyRspnsService.selectSrvyQitemArtclList(searchParams);

            model.addAttribute("srvyInfo", srvyInfo);
            model.addAttribute("questionList", questionList);
            model.addAttribute("itemList", itemList);
            model.addAttribute("srvyId", srvySn);
            model.addAttribute("participantId", participantId);
            model.addAttribute("basePath", BASE_PATH);

        } catch (Exception e) {
            model.addAttribute("errorMessage", "설문조사를 불러오는 중 오류가 발생했습니다.");
            return VIEW_PREFIX + "error";
        }

        return VIEW_PREFIX + "participate";
    }

    @PostMapping("/submit")
    public String submitSrvy(@RequestParam Map<String, Object> params,
                               HttpServletRequest request,
                               ModelMap model) {
        try {
            String srvyId = (String) params.get("srvyId");
            String participantId = (String) params.get("participantId");

            // 설문조사 상태 체크
            if (srvyId != null && !srvyId.isEmpty()) {
                SrvyVO srvyVO = new SrvyVO();
                srvyVO.setSrvySn(Integer.parseInt(srvyId));
                SrvyVO srvyInfo = srvyService.selectSrvyDetail(srvyVO);

                if (srvyInfo != null) {
                    // 내부 설문(SRVYTRGTTY002)만 허용
                    if (!"SRVYTRGTTY002".equals(srvyInfo.getTrgtType())) {
                        model.addAttribute("errorMessage", "잘못된 접근경로입니다.");
                        return VIEW_PREFIX + "error";
                    }
                    if (isSurveyExpired(srvyInfo.getSrvyEndYmd())) {
                        model.addAttribute("errorMessage", "이 설문조사는 종료되었습니다.");
                        return VIEW_PREFIX + "error";
                    }
                }
            }

            Integer respondentSn;
            String participantName = "public_user";

            // 로컬스토리지에서 전달받은 참여자 정보 사용
            String participantInfoJson = (String) params.get("participantInfo");
            Map<String, Object> participantInfo = null;

            if (participantInfoJson != null && !participantInfoJson.isEmpty()) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> parsedInfo = objectMapper.readValue(participantInfoJson, Map.class);
                    participantInfo = parsedInfo;
                } catch (Exception e) {
                    log.warn("참여자 정보 JSON 파싱 실패: {}", e.getMessage());
                }
            }

            if (participantInfo != null) {
                respondentSn = saveParticipantFromMap(participantInfo);
                participantName = (String) participantInfo.get("srvyRspdntNm");
            } else {
                if (participantId != null && !participantId.isEmpty()) {
                    respondentSn = Integer.parseInt(participantId);

                    try {
                        SrvyRspdntVO participant = new SrvyRspdntVO();
                        participant.setSrvyRspdntSn(respondentSn);
                        SrvyRspdntVO participantInfoFromDb = srvyRspdntService.selectSrvyRspdntDetail(participant);
                        if (participantInfoFromDb != null && participantInfoFromDb.getRspdntNm() != null) {
                            participantName = participantInfoFromDb.getRspdntNm();
                        }
                    } catch (Exception e) {
                        log.warn("참여자 정보 조회 실패, 기본값 사용: {}", e.getMessage());
                    }
                } else {
                    respondentSn = (int) System.currentTimeMillis();
                }
            }

            List<SrvyRspnsVO> responseList = new ArrayList<>();
            Set<String> processedQuestions = new HashSet<>();

            for (String key : params.keySet()) {
                if (key.startsWith("question_")) {
                    String questId = key.substring(9);

                    if (questId.endsWith("[]")) {
                        questId = questId.substring(0, questId.length() - 2);
                    }
                    if (questId.endsWith("_checkbox")) {
                        questId = questId.substring(0, questId.length() - 9);
                    }
                    if (processedQuestions.contains(questId)) {
                        continue;
                    }
                    processedQuestions.add(questId);

                    String[] paramValues = request.getParameterValues("question_" + questId);

                    if (paramValues != null && paramValues.length > 1) {
                        for (String val : paramValues) {
                            SrvyRspnsVO response = createResponseVO(srvyId, questId, val, respondentSn, participantName);
                            responseList.add(response);
                        }
                    } else {
                        Object value = params.get(key);
                        if (value != null && !value.toString().trim().isEmpty()) {
                            SrvyRspnsVO response = createResponseVO(srvyId, questId, value.toString(), respondentSn, participantName);
                            responseList.add(response);
                        }
                    }
                }
            }

            for (String key : params.keySet()) {
                if (key.startsWith("ETC_")) {
                    String itemId = key.substring(4);
                    String etcAnswer = (String) params.get(key);
                    if (etcAnswer != null && !etcAnswer.trim().isEmpty()) {
                        updateEtcAnswer(responseList, itemId, etcAnswer);
                    }
                }
            }

            if (!responseList.isEmpty()) {
                log.info("응답 리스트 크기: {}", responseList.size());
                for (SrvyRspnsVO response : responseList) {
                    log.info("응답 데이터 - 설문ID: {}, 문항ID: {}, 선택지ID: {}, 응답내용: {}",
                            response.getSrvySn(), response.getQitemSn(), response.getArtclSn(), response.getRspnsCn());
                }
                log.info("다중 응답 저장 시작");
                srvyRspnsService.insertMultipleResponses(responseList);
                log.info("다중 응답 저장 완료");
            }

            model.addAttribute("srvyId", srvyId);
            model.addAttribute("respondentName", params.get("respondentNm"));

        } catch (Exception e) {
            log.error("설문 응답 제출 중 오류 발생", e);
            model.addAttribute("errorMessage", "설문 응답 제출 중 오류가 발생했습니다: " + e.getMessage());
            return VIEW_PREFIX + "error";
        }

        return VIEW_PREFIX + "complete";
    }

    private Integer saveParticipantFromMap(Map<String, Object> participantInfo) {
        try {
            SrvyRspdntVO participant = new SrvyRspdntVO();
            participant.setSrvySn(Integer.parseInt((String) participantInfo.get("srvySn")));

            String trgtType = (String) participantInfo.get("trgtType");
            String participantType = (String) participantInfo.get("participantType");

            // RequestContext에서 세션 정보 가져오기
            LoginVO loginUser = RequestContext.getCurrentUser();
            boolean isLoggedIn = loginUser != null && loginUser.getUserId() != null
                && !loginUser.getUserId().isEmpty()
                && !"ANONYMOUS".equalsIgnoreCase(loginUser.getUserId());

            boolean isInternal = "SRVYTRGTTY002".equals(trgtType) || "INTERNAL".equals(participantType);

            if (isInternal) {
                if (!isLoggedIn) {
                    throw new RuntimeException("로그인이 필요합니다. 내부 직원은 로그인 후 설문조사에 참여해주세요.");
                }
                participant.setRspdntId(loginUser.getUserId());
                participant.setRspdntNm(loginUser.getUserNm() != null ? loginUser.getUserNm() : loginUser.getUserId());
                participant.setDeptCd(loginUser.getDeptCd());
                participant.setJbgdCd(loginUser.getJbgdCd());
            } else {
                participant.setRspdntId("anonymous_" + System.currentTimeMillis());
                participant.setRspdntNm("anonymous");
            }

            participant.setGndrCd((String) participantInfo.get("srvyRspdntGender"));
            participant.setAgeGrpCd((String) participantInfo.get("ageGrpCd"));

            String regUserId = isLoggedIn ? loginUser.getUserId() : "anonymous";
            participant.setFrstRegId(regUserId);
            participant.setLastMdfcnId(regUserId);

            srvyRspdntService.insertSrvyRspdnt(participant);

            return participant.getSrvyRspdntSn();

        } catch (Exception e) {
            log.error("참여자 정보 저장 중 오류 발생", e);
            throw new RuntimeException("참여자 정보 저장 중 오류가 발생했습니다.", e);
        }
    }

    private SrvyRspnsVO createResponseVO(String srvyId, String questId, String value,
                                            Integer respondentSn, String participantName) {
        SrvyRspnsVO response = new SrvyRspnsVO();
        response.setSrvySn(Integer.parseInt(srvyId));
        response.setQitemSn(Integer.parseInt(questId));
        response.setSrvyRspdntSn(respondentSn);
        response.setSrvyRspnsCrtUserId(participantName);
        response.setSrvyRspnsChgUserId(participantName);
        response.setFrstRegId(participantName);
        response.setLastMdfcnId(participantName);

        log.info("응답 VO 생성 - 설문ID: {}, 문항ID: {}, 값: {}, 응답자ID: {}", srvyId, questId, value, respondentSn);

        if (value.startsWith("ITEM_")) {
            Integer artclSn = Integer.parseInt(value.substring(5));
            response.setArtclSn(artclSn);
            log.info("객관식 응답 - 선택지ID: {}", artclSn);
        } else {
            response.setRspnsCn(value);
            response.setArtclSn(null);
            log.info("주관식 응답 - 내용: {}", value);
        }

        return response;
    }

    private void updateEtcAnswer(List<SrvyRspnsVO> responseList, String itemId, String etcAnswer) {
        for (SrvyRspnsVO response : responseList) {
            if (itemId.equals(response.getArtclSn().toString())) {
                response.setEtcRspnsCn(etcAnswer);
                break;
            }
        }
    }

    private boolean isSurveyExpired(String endDate) {
        try {
            LocalDate currentDate = LocalDate.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDate end = LocalDate.parse(endDate, formatter);
            return currentDate.isAfter(end);
        } catch (Exception e) {
            log.error("설문조사 종료일 확인 중 오류 발생: {}", e.getMessage());
            return false;
        }
    }

    private String getCurrentUserId(HttpServletRequest request) {
        try {
            Authentication authentication = (Authentication) request.getUserPrincipal();
            if (authentication != null) {
                LoginVO loginVO = (LoginVO) authentication.getPrincipal();
                if (loginVO != null && loginVO.getUserId() != null) {
                    return loginVO.getUserId();
                }
            }
            return "unknown";
        } catch (Exception e) {
            log.warn("인증 정보에서 사용자 아이디를 가져올 수 없습니다: {}", e.getMessage());
            return "unknown";
        }
    }
}
