package cokr.xit.fims.excl.web;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import cokr.xit.applib.Print;
import cokr.xit.base.code.CommonCode;
import cokr.xit.base.docs.xls.CellDef;
import cokr.xit.base.docs.xls.Format;
import cokr.xit.base.docs.xls.Style;
import cokr.xit.base.docs.xls.XLSWriter;
import cokr.xit.base.file.FileInfo;
import cokr.xit.base.file.service.FileService;
import cokr.xit.base.file.web.FileInfoFactory;
import cokr.xit.base.web.ApplicationController;
import cokr.xit.fims.base.service.bean.OgdpBean;
import cokr.xit.fims.cmmn.FimsPrintOption;
import cokr.xit.fims.cmmn.hwp.format.DlbrDecsnList;
import cokr.xit.fims.cmmn.service.bean.StngBean;
import cokr.xit.fims.cmmn.xls.FormatMaker;
import cokr.xit.fims.cmmn.xls.StyleMaker;
import cokr.xit.fims.excl.LevyExclQuery;
import cokr.xit.fims.excl.OpnnDlbrMbr;
import cokr.xit.fims.excl.OpnnSbmsn;
import cokr.xit.fims.excl.service.OpnnDlbrMbrService;
import cokr.xit.fims.excl.service.OpnnSbmsnService;
import cokr.xit.fims.task.Task;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.data.DataObject;

/**의견제출 대장 서비스의 웹 컨트롤러
 *
 * <p>상세 설명:
 *
 * <pre>
 * ============ 변경 이력 ============
 * 2023-06-27	JoJH 최초 작성
 * ================================
 * </pre>
 */
@Controller
@RequestMapping(name="의견제출 관리", value=Excl02Controller.CLASS_URL)
public class Excl02Controller extends ApplicationController {

	public static final String CLASS_URL = "/excl/excl02";

	public class METHOD_URL {
		public static final String
			  opinionSubmissionMain				= "/010/main.do"				// 의견제출 관리 메인 화면
			, getOpinionSubmissionList			= "/010/list.do"				// 의견제출 대장 목록 조회
			, makeDlbrDecsnFileFromHwpFormat	= "/010/makeHwp.do"				// 의견제출 심의의결서 HWP 저장
			, removeOpinionSubmission			= "/010/remove.do"				// 의견제출 대장 삭제
			, getOpinionSubmissionInfo			= "/020/info.do"				// 의견제출 대장 조회
			, createOpinionSubmission			= "/020/create.do"				// 의견제출 대장 등록
			, updateOpinionSubmission			= "/020/update.do"				// 의견제출 대장 수정
			, getOpinionSubmissionAnswerInfo	= "/030/info.do"				// 의견제출 대장 심의 조회
			, updateOpinionSubmissionAnswer		= "/030/update.do"				// 의견제출 대장 심의 수정
			, getOpinionDeliberationMemberInfo	= "/040/info.do"				// 의견제출 심의 회원 조회
			, createOpinionDeliberationMember	= "/040/create.do"				// 의견제출 심의 회원 등록
			, updateOpinionDeliberationMember	= "/040/update.do"				// 의견제출 심의 회원 수정
		;
	}

	/** 의견제출 대장 서비스 */
	@Resource(name="opnnSbmsnService")
	protected OpnnSbmsnService opnnSbmsnService;
	/**의견제출 심의 회원 서비스*/
	@Resource(name = "opnnDlbrMbrService")
	private OpnnDlbrMbrService opnnDlbrMbrService;
	/** 파일 정보 서비스 서비스 */
	@Resource(name="fileService")
	private FileService fileService;
	/**설정 정보 Bean */
	@Resource(name="stngBean")
	private StngBean stngBean;
	@Resource(name = "ogdpBean")
	private OgdpBean ogdpBean;

	/**의견제출 대장 관리 메인화면(fims/excl/excl02/010-main)을 연다.
	 *
	 * @return /fims/excl/excl02010
	 */
	@RequestMapping(name="의견제출 관리 메인", value = METHOD_URL.opinionSubmissionMain)
	public ModelAndView opinionSubmissionMain() {
		// View(jsp)에서 사용할 공통코드를 조회
		Map<String, List<CommonCode>> commonCodes = getCodesOf("FIM029", "FIM030", "FIM031", "FIM033", "FIM054");

		return new ModelAndView("fims/excl/excl02010-main")
			.addObject("pageName", "excl02010")                             // View(jsp)에서 사용할 id 뒤에 붙일 suffix
			.addObject("prefixUrl", CLASS_URL)                              // prefixUrl
			.addObject("sggCd", currentUser().getOrgID())                        // 시군구 코드(SGG_CD)
			.addObject("taskListForSgg", stngBean.filterTaskSectionCodeForSgg(commonCodes.get("FIM054")))	// 업무 구분 코드(TASK_SE_CD)
			.addObject("FIM029List", commonCodes.get("FIM029"))             // 의견제출 접수 방법(RCPT_SE_CD)
			.addObject("FIM030List", commonCodes.get("FIM030"))             // 의견제출 결과 통보 방법(NTFCTN_SE_CD)
			.addObject("FIM031List", commonCodes.get("FIM031"))             // 의견 제출 답변 결과(OPNN_SBMSN_STTS_CD)
			.addObject("FIM033List", commonCodes.get("FIM033"))             // 의견제출 구분 코드(OPNN_SBMSN_SE_CD)
		;
	}

	/**의견제출 대장 목록을 조회하여 반환한다.
	 * {@link OpnnSbmsnService#getOpnnSbmsnList(Excl02Query)} 참고
	 * @param req 의견제출 대장 조회 조건
	 * @return jsonView
	 * <pre><code> {
	 *     "opnnSbmsnList": [의견제출 대장 목록]
	 *     "opnnSbmsnStart": 의견제출 대장 목록 시작 인덱스
	 *     "opnnSbmsnFetch": 한 번에 가져오는 의견제출 대장 목록 수
	 *     "opnnSbmsnTotal": 조회 결과 찾은 전체 의견제출 대장 수
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 목록 조회", value=METHOD_URL.getOpinionSubmissionList)
	public ModelAndView getOpinionSubmissionList(LevyExclQuery req) {
		if (!"xls".equals(req.getDownload())) {
			List<?> result = opnnSbmsnService.getOpnnSbmsnList(setFetchSize(req));
			return setPagingInfo(new ModelAndView("jsonView"), result, "");
		} else {
			// 현재 날짜 구하기
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
			String dateTime = dateFormat.format(System.currentTimeMillis());

			List<CellDef> cellDefs = fromJson(req.getCellDefs(), CellDef.listType());

			XLSWriter xlsx = new XLSWriter().worksheet(0);
			Format format = new Format(xlsx);
			CellStyle center = format.cellStyle(Style.CENTER);
			CellStyle numeric = format.n_nn0();
			CellStyle dateYMD = format.yyyy_mm_dd();
			CellStyle dateDT = format.yyyy_mm_dd_hh_mm_ss();

			List<DataObject> list = opnnSbmsnService.getOpnnSbmsnList(req.setFetchSize(0));

			Map<String,Object> valueMap = new HashMap<String,Object>();
			valueMap.put("업무구분", format.of("TASK_SE_NM").style(center));
			valueMap.put("접수번호", format.of("RCPT_NO").style(center));
			valueMap.put("접수일자", FormatMaker.yyyy_mm_dd(format, "RCPT_YMD").style(dateYMD));
			valueMap.put("접수구분", format.of("RCPT_SE_NM").style(center));
			valueMap.put("통보구분", format.of("NTFCTN_SE_NM").style(center));
			valueMap.put("소유주관계", format.of("OWNR_REL_NM").style(center));
			valueMap.put("진술자명", format.of("STTR_NM"));
			valueMap.put("진술자생일", format.of("STTR_BRDT_MASK").style(center));
			valueMap.put("진술자우편번호", format.of("STTR_ZIP").style(center));
			valueMap.put("진술자주소", format.of("STTR_ADDR"));
			valueMap.put("진술자상세주소", format.of("STTR_DADDR"));
			valueMap.put("의견제출상태", format.of("OPNN_SBMSN_STTS_NM").style(center));
			valueMap.put("의견제출분류", format.of("OPNN_SBMSN_SE_NM"));
			valueMap.put("의견제출요지", format.of("OPNN_SBMSN_GIST"));
			valueMap.put("문서번호", format.of("DOC_NO"));
			valueMap.put("답변일자", FormatMaker.yyyy_mm_dd(format, "ANS_YMD").style(dateYMD));
			valueMap.put("답변내용", format.of("ANS_CN"));
			valueMap.put("단속일시", FormatMaker.yyyy_mm_dd_hh_mm_ss(format, "CRDN_YMD_TM").style(dateDT));
			valueMap.put("차량번호", format.of("VHRNO"));
			valueMap.put("납부자구분", format.of("RTPYR_SE_NM").style(center));
			valueMap.put("납부자번호", format.of("RTPYR_NO").style(center));
			valueMap.put("납부자명", format.of("RTPYR_NM"));
			valueMap.put("단속법정동", format.of("CRDN_STDG_NM").style(center));
			valueMap.put("단속장소", format.of("CRDN_PLC"));
			valueMap.put("상세단속장소", format.of("DTL_CRDN_PLC"));
			valueMap.put("위반항목", format.of("VLTN_ARTCL"));
			valueMap.put("단속원금", format.of("FFNLG_CRDN_AMT").style(numeric));
			valueMap.put("과태료금액", format.of("FFNLG_AMT").style(numeric));
			valueMap.put("처리상태", format.of("CRDN_STTS_NM"));
			valueMap.put("단속특별구역", format.of("CRDN_SPAREA_NM").style(center));
			valueMap.put("사용연료", format.of("USE_FUEL_NM").style(center));
			valueMap.put("주차가능여부", format.of("PRK_PSBLTY_RSLT_NM").style(center));
			valueMap.put("우편번호", format.of("ZIP").style(center));
			valueMap.put("주소", format.of("ADDR"));
			valueMap.put("상세주소", format.of("DTL_ADDR"));
			valueMap.put("등록일시", FormatMaker.yyyy_mm_dd_hh_mm_ss(format, "REG_DT").style(dateDT));
			valueMap.put("등록사용자", format.of("RGTR_NM").style(center));
			valueMap.put("수정일시", FormatMaker.yyyy_mm_dd_hh_mm_ss(format, "MDFCN_DT").style(dateDT));
			valueMap.put("수정사용자", format.of("MDFR_NM").style(center));

			CellDef.setValues(cellDefs, valueMap);

			xlsx.cell(0, 0).value("의견제출").value(center).merge(0, cellDefs.size() - 1)
				.cell(3, 0).rowValues(CellDef.header(cellDefs, () -> StyleMaker.headerStyle(xlsx)))
				.cell(4, 0).values(list, CellDef.values(cellDefs.stream().map(i -> {if(i.getValue() instanceof Format) {i.setField(null);}; return i;}).toList()));

			return new ModelAndView("downloadView")
				.addObject("download", xlsx.getDownloadable().setFilename("의견제출" + "_목록_" + dateTime + ".xlsx"));
		}
	}

	/**의견제출 정보를 조회하여 반환한다.
	 * @param req 의견제출 대장 조회 조건
	 * @return fims/excl/excl02020-info 또는 jsonView
	 * <pre>{
	 *     "opnnSbmsnInfo": 의견제출 정보
	 * }</pre>
	 */
	@Task
	@RequestMapping(name="의견제출 정보 조회", value=METHOD_URL.getOpinionSubmissionInfo)
	public ModelAndView getOpinionSubmissionInfo(HttpServletRequest hReq, LevyExclQuery req) {
        // 상세 정보 조회
        DataObject opnnSbmsnInfo = opnnSbmsnService.getOpnnSbmsnInfo(req);
		// View(jsp)에서 사용할 공통코드를 조회
		Map<String, List<CommonCode>> commonCodes = getCodesOf("FIM019", "FIM029", "FIM030", "FIM032", "FIM033", "FIM054");

		boolean json = jsonResponse();
		return new ModelAndView(json ? "jsonView" : "fims/excl/excl02020-info")
			.addObject("callPurpose", req.getCallPurpose())                     // 호출 용도
			.addObject("pageName", "excl02020")                                 // jsp pageName
			.addObject("prefixUrl", CLASS_URL)                                  // prefixUrl
			.addObject("FIM019List", commonCodes.get("FIM019"))                 // 감경 사유 구분 코드(RDCT_RSN_CD)
			.addObject("FIM029List", commonCodes.get("FIM029"))                 // 접수 구분 코드(RCPT_SE_CD)
			.addObject("FIM030List", commonCodes.get("FIM030"))                 // 통보 구분 코드(NTFCTN_SE_CD)
			.addObject("FIM032List", commonCodes.get("FIM032"))                 // 소유주 관계 구분 코드(OWNR_REL_CD)
			.addObject("FIM033List", commonCodes.get("FIM033"))                 // 의견 제출 구분 코드(OPNN_SBMSN_SE_CD)
			.addObject("Info", json ? opnnSbmsnInfo : toJson(opnnSbmsnInfo))    // 의견제출 정보
		;
	}

	/**의견제출 대장를 등록한다.
	 * @param opnnSbmsn 의견제출 정보, 이미지 파일 uploadFiles
	 * @return jsonView
	 * <pre><code> {
	 *     "saved": 등록되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 등록", value=METHOD_URL.createOpinionSubmission)
	public ModelAndView createOpinionSubmission(OpnnSbmsn opnnSbmsn, MultipartFile[] uploadFiles) {
		// 첨부 파일
		List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
		if (uploadFiles != null && uploadFiles.length > 0) {
			fileInfoList = new FileInfoFactory().makeFileInfos(null, uploadFiles);
		}

		String rtnMsg = opnnSbmsnService.createOpnnSbmsn(opnnSbmsn, fileInfoList);

		return new ModelAndView("jsonView")
				.addObject("saved", rtnMsg.contains("[S]"))
				.addObject("rtnMsg", rtnMsg);
	}

	/**의견제출 대장을 수정한다.
	 * @param opnnSbmsn 의견제출 정보, 이미지 파일 uploadFiles
	 * @return jsonView
	 * <pre><code> {
	 *     "saved": 수정되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 수정", value=METHOD_URL.updateOpinionSubmission)
	public ModelAndView updateOpinionSubmission(OpnnSbmsn opnnSbmsn, MultipartFile[] uploadFiles) {
		// 첨부 파일
		List<FileInfo> fileInfoList = new ArrayList<FileInfo>();
		if (uploadFiles != null && uploadFiles.length > 0) {
			fileInfoList = new FileInfoFactory().makeFileInfos(null, uploadFiles);
		}
		String rtnMsg = opnnSbmsnService.updateOpnnSbmsn(opnnSbmsn, fileInfoList);

		return new ModelAndView("jsonView")
			.addObject("saved", rtnMsg.contains("[S]"))
			.addObject("rtnMsg", rtnMsg);
	}

	/**의견제출 심의 정보를 조회하여 반환한다.
	 * @param req 의견제출 대장 조회 조건
	 * @return fims/excl/excl02030-info 또는 jsonView
	 * <pre>{
	 *     "opnnSbmsnInfo": 의견제출 정보
	 * }</pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 심의 정보 조회", value=METHOD_URL.getOpinionSubmissionAnswerInfo)
	public ModelAndView getOpinionSubmissionAnswerInfo(HttpServletRequest hReq, LevyExclQuery req) {
        DataObject opnnSbmsnInfo = opnnSbmsnService.getOpnnSbmsnInfo(req);
		// View(jsp)에서 사용할 공통코드를 조회
		Map<String, List<CommonCode>> commonCodes = getCodesOf("FIM019", "FIM030", "FIM031", "FIM033", "FIM054");

		boolean json = jsonResponse();
		return new ModelAndView(json ? "jsonView" : "fims/excl/excl02030-info")
			.addObject("callPurpose", req.getCallPurpose())                     // 호출 용도
			.addObject("pageName", "excl02030")                                 // jsp pageName
            .addObject("prefixUrl", CLASS_URL)                                  // prefixUrl
			.addObject("FIM019List", commonCodes.get("FIM019"))                 // 감경 사유 구분 코드(RDCT_RSN_CD)
			.addObject("FIM030List", commonCodes.get("FIM030"))                 // 통보 구분 코드(NTFCTN_SE_CD)
			.addObject("FIM031List", commonCodes.get("FIM031"))                 // 의견 제출 상태 코드(OPNN_SBMSN_STTS_CD)
			.addObject("FIM033List", commonCodes.get("FIM033"))                 // 의견 제출 구분 코드(OPNN_SBMSN_SE_CD)
			.addObject("Info", json ? opnnSbmsnInfo : toJson(opnnSbmsnInfo))    // 의견제출 정보
		;
	}

	/**의견제출 심의 정보를 수정한다.
	 * @param opnnSbmsn 의견제출 대장 정보
	 * @return jsonView
	 * <pre><code> {
	 *     "saved": 수정되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 심의정보 수정", value=METHOD_URL.updateOpinionSubmissionAnswer)
	public ModelAndView updateOpinionSubmissionAnswer(OpnnSbmsn opnnSbmsn) {
		String rtnMsg = opnnSbmsnService.updateOpnnSbmsnAnswer(opnnSbmsn);

		return new ModelAndView("jsonView")
			.addObject("saved", rtnMsg.contains("[S]"))
			.addObject("rtnMsg", rtnMsg);
	}

	/**지정한 조건에 따라 의견제출 심의 의결서를 출력한다.
	 * @param req 의견제출 대장 조회 조건
	 * @return jsonView
	 * <pre><code> {
	 *     "affected": 저장된 정보수
	 *     "saved": 저장되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 심의의결서 출력", value=METHOD_URL.makeDlbrDecsnFileFromHwpFormat)
	public ModelAndView makeDlbrDecsnFileFromHwpFormat(LevyExclQuery req) {
		UserInfo userInfo = currentUser();
		ogdpBean.initUserInfo(userInfo);

		Print print = new Print();
		print.setPrintRequestUserInfo(userInfo);

		FimsPrintOption printOption = new FimsPrintOption();

		List<DataObject> dataObjectList = opnnSbmsnService.getOpnnSbmsnDlbrDecsns(req);

		DlbrDecsnList hwpFormat = new DlbrDecsnList(print, printOption, dataObjectList);
		HashMap<String, Object> result = hwpFormat.makeFile().andDownload();

		return new ModelAndView("downloadView")
			.addAllObjects(result);
	}

	/**지정한 의견제출 대장을 제거한다.
	 * @param opnnSbmsn 의견제출 정보
	 * @return jsonView
	 * <pre><code> {
	 *     "affected": 저장된 정보수
	 *     "saved": 저장되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 대장 삭제", value=METHOD_URL.removeOpinionSubmission)
	public ModelAndView removeOpinionSubmission(OpnnSbmsn opnnSbmsn) {
		String rtnMsg = "";

		if (opnnSbmsn.getOpnnIds() == null || opnnSbmsn.getOpnnIds().length < 1) {
			rtnMsg = opnnSbmsnService.removeOpnnSbmsn(opnnSbmsn);
		} else {
			// 의견제출 Ids 만큼 삭제 반복..
			for (String opnnId : opnnSbmsn.getOpnnIds()) {
				OpnnSbmsn deltOpnnSbmsn = new OpnnSbmsn();
				deltOpnnSbmsn.setOpnnId(opnnId);
				deltOpnnSbmsn.setDelRsn(opnnSbmsn.getDelRsn());

				// 의견제출 삭제 호출
				rtnMsg = opnnSbmsnService.removeOpnnSbmsn(deltOpnnSbmsn);
				if (!rtnMsg.contains("[S]"))									// 오류가 발생하였으면 종료..
					break;
			}
		}

		return new ModelAndView("jsonView")
			.addObject("saved", rtnMsg.contains("[S]"))
			.addObject("rtnMsg", rtnMsg);
	}

	/**의견제출 심의 회원 정보를 조회하여 반환한다.
	 * @param req 의견제출 대장 조회 조건
	 * @return fims/excl/excl02040-info 또는 jsonView
	 * <pre>{
	 *     "opnnDlbrMbrInfo": 의견제출 심의 회원 정보
	 * }</pre>
	 */
	@Task
	@RequestMapping(name="의견제출 심의 회원 정보 조회", value=METHOD_URL.getOpinionDeliberationMemberInfo)
	public ModelAndView getOpinionDeliberationMemberInfo(HttpServletRequest hReq, LevyExclQuery req) {
        DataObject opnnDlbrMbrinfo = opnnDlbrMbrService.getOpnnDlbrMbrInfo(req);

		boolean json = jsonResponse();
        return new ModelAndView(json ? "jsonView" : "fims/excl/excl02040-info")
            .addObject("callPurpose", req.getCallPurpose())                         // 호출 용도
            .addObject("pageName", "excl02040")                                     // jsp pageName
            .addObject("prefixUrl", CLASS_URL)                                      // prefixUrl
            .addObject("Info", json ? opnnDlbrMbrinfo : toJson(opnnDlbrMbrinfo))    // 의견제출 심의 회원 정보
		;
	}

	/**의견제출 심의 회원를 등록한다.
	 * @param opnnDlbrMbr 의견제출 심의 회원 정보
	 * @return jsonView
	 * <pre><code> {
	 *     "saved": 등록되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 심의 회원 등록", value=METHOD_URL.createOpinionDeliberationMember)
	public ModelAndView create(OpnnDlbrMbr opnnDlbrMbr) {
		String rtnMsg = opnnDlbrMbrService.createOpnnDlbrMbr(opnnDlbrMbr);

		return new ModelAndView("jsonView")
			.addObject("saved", rtnMsg.contains("[S]"))
			.addObject("rtnMsg", rtnMsg);
	}

	/**의견제출 심의 회원 정보를 수정한다.
	 * @param opnnDlbrMbr 의견제출 심의 회원 정보
	 * @return jsonView
	 * <pre><code> {
	 *     "saved": 수정되었으면 true, 그렇지 않으면 false
	 * }</code></pre>
	 */
	@Task
	@RequestMapping(name="의견제출 심의 회원 수정", value=METHOD_URL.updateOpinionDeliberationMember)
	public ModelAndView update(OpnnDlbrMbr opnnDlbrMbr) {
		String rtnMsg = opnnDlbrMbrService.updateOpnnDlbrMbr(opnnDlbrMbr);

		return new ModelAndView("jsonView")
			.addObject("saved", rtnMsg.contains("[S]"))
			.addObject("rtnMsg", rtnMsg);
	}
}