package cokr.xit.fims.levy.web;

import java.text.SimpleDateFormat;
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.servlet.ModelAndView;

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.web.ApplicationController;
import cokr.xit.fims.cmmn.CmmnQuery;
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.levy.LevyQuery;
import cokr.xit.fims.levy.service.LevyService;
import cokr.xit.fims.mngt.service.bean.TaskBean;
import cokr.xit.fims.mngt.service.bean.TaskProcessor;
import cokr.xit.fims.task.Task;
import cokr.xit.foundation.data.DataObject;

/**부과 대장 서비스의 웹 컨트롤러
 *
 * <p>상세 설명:
 *
 * <pre>
 * ============ 변경 이력 ============
 * 2023-08-30    JoJH 최초 작성
 * ================================
 * </pre>
 */
@Controller
@RequestMapping(name="부과", value=Levy01Controller.CLASS_URL)
public class Levy01Controller extends ApplicationController {

    public static final String CLASS_URL = "/levy/levy01";

    public class METHOD_URL {
        public static final String
              reductionLevyTargetMain       = "/010/main.do"                    // 사전 감경부과 대상 메인 화면
            , getReductionLevyTargetList    = "/010/list.do"                    // 사전 감경부과 대상 대장 목록 조회
            , getReductionLevyTargetInfo    = "/020/info.do"                    // 사전 감경부과 대상 정보
            , createReductionLevyList       = "/020/createRdctLevyList.do"      // 사전 감경부과 등록
            , levyMain                      = "/050/main.do"                    // 부과 관리 메인 화면
            , getLevyList                   = "/050/list.do"                    // 부과 대장 목록 조회
        ;
    }

    /**부과 대장 서비스*/
    @Resource(name="levyService")
    private LevyService levyService;
    /**업무 정보 서비스 */
    @Resource(name="taskBean")
    private TaskBean taskBean;
    /**설정 정보 Bean */
    @Resource(name="stngBean")
    private StngBean stngBean;

    /**사전 감경부과 대상 메인화면(levy/levy01010-main)을 연다.
     * @return
     */
    @RequestMapping(name="사전 감경부과 등록 메인", value=METHOD_URL.reductionLevyTargetMain)
    public ModelAndView reductionLevyTargetMain() {
        // View(jsp)에서 사용할 공통코드를 조회
        List<String> cdGrps = TaskProcessor.get().getVltnCdGrps();
        cdGrps.add("FIM054");
        String[] groupIDs = cdGrps.toArray(new String[cdGrps.size()]);

        Map<String, List<CommonCode>> commonCodes = getCodesOf(groupIDs);
        return addCodes(commonCodes, new ModelAndView("fims/levy/levy01010-main"), groupIDs)
			.addObject("pageName", "levy01010")           // 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)
        ;
    }

    /**사전 감경부과 대상 목록을 조회하여 반환한다.
     * {@link LevyService#getRdctLevyTrgtList(LevyQuery)} 참고
     * @param req 부과 대장 조회 조건
     * @return jsonView
     * <pre><code> {
     *     "levyList": [부과 대장 목록]
     *     "levyStart": 부과 대장 목록 시작 인덱스
     *     "levyFetch": 한 번에 가져오는 부과 대장 목록 수
     *     "levyTotal": 조회 결과 찾은 전체 부과 대장 수
     * }</code></pre>
     */
    @Task({"PVS","BPV"})
    @RequestMapping(name="사전 감경부과 대상 목록 조회", value=METHOD_URL.getReductionLevyTargetList)
    public ModelAndView getReductionLevyTargetList(LevyQuery req) {
        if (!"xls".equals(req.getDownload())) {
            List<?> result = levyService.getRdctLevyTrgtList(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 = levyService.getRdctLevyTrgtList(req.setFetchSize(0));

            Map<String,Object> valueMap = new HashMap<String,Object>();
            valueMap.put("업무구분", format.of("TASK_SE_NM").style(center));
            valueMap.put("단속일시", FormatMaker.yyyy_mm_dd_hh_mm_ss(format, "CRDN_YMD_TM").style(dateDT));
            valueMap.put("차량번호", format.of("VHRNO"));
            valueMap.put("법정동", format.of("CRDN_STDG_NM"));
            valueMap.put("단속장소", format.of("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("민원접수일자", FormatMaker.yyyy_mm_dd(format, "CVLCPT_RCPT_YMD").style(dateYMD));
            valueMap.put("민원신청번호", format.of("CVLCPT_APLY_NO").style(center));
            valueMap.put("민원접수번호", format.of("CVLCPT_RCPT_NO").style(center));
            valueMap.put("민원담당자", format.of("CVLCPT_PRCS_PIC_NM").style(center));
            valueMap.put("민원처리일시", FormatMaker.yyyy_mm_dd(format, "CVLCPT_PRCS_CMPTN_DT").style(dateYMD));
            valueMap.put("민원전송결과", format.of("CVLCPT_TRSM_NM").style(center));
            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("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"));
        }
    }

    /**감경 부과 대상 정보(info)를 반환한다.
     * @param req 부과 대장 조회 조건
     * @return fims/levy/levy01020-info 또는 jsonView
     * <pre>{
     *     "rdctLevyYmdInfo": 감경 부과 정보
     * }</pre>
     */
    @Task({"PVS","BPV"})
    @RequestMapping(name="사전 감경부과 정보 조회", value=METHOD_URL.getReductionLevyTargetInfo)
    public ModelAndView getReductionLevyTargetInfo(HttpServletRequest hReq, LevyQuery req) {
        // 감경 부과일자
        DataObject info = taskBean.getAdvntceYmdInfo(
        	new CmmnQuery()
        		.setSggCd(req.getSggCd())
                .setTaskSeCd(req.getTaskSeCd())
        );

        // 이전에 조회되었던 총건수, 금액
        info.put("TNOCS", req.getTnocs());
        info.put("GRAMT_FFNLG_AMT", req.getGramtFfnlgAmt());
        info.put("GRAMT_ADVNTCE_AMT", req.getGramtAdvntceAmt());

        boolean json = jsonResponse();
        return new ModelAndView(json ? "jsonView" : "fims/levy/levy01020-info")
            .addObject("callPurpose", req.getCallPurpose())                    // 호출 용도
            .addObject("pageName", "levy01020")                                // jsp pageName
            .addObject("prefixUrl", CLASS_URL)                                // prefixUrl
            .addObject("mainQuery", json ? req : toJson(req))                // 검색 조건
            .addObject("Info", json ? info : toJson(info))
        ;
    }

    /**감경부과 대상자료를 부과 대장를 등록한다.
     * @param levy 부과 대장 정보
     * @return jsonView
     * <pre><code> {
     *     "saved": 등록되었으면 true, 그렇지 않으면 false
     * }</code></pre>
     */
    @Task({"PVS","BPV"})
    @RequestMapping(name="사전 감경부과 대장 등록", value=METHOD_URL.createReductionLevyList)
    public ModelAndView createReductionLevyList(LevyQuery req) {
        String rtnMsg = levyService.createRdctLevyList(req);

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

    /**부과 관리 메인화면(levy/levy01050-main)을 연다.
     * @return
     */
    @RequestMapping(name="부과 관리 메인", value=METHOD_URL.levyMain)
    public ModelAndView levyMain() {
        // View(jsp)에서 사용할 공통코드를 조회
        Map<String, List<CommonCode>> commonCodes = getCodesOf("FIM010", "FIM046", "FIM054");

        return new ModelAndView("fims/levy/levy01050-main")
            .addObject("pageName", "levy01050")                                // 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("FIM010List", commonCodes.get("FIM010"))                // 단속 상태 코드(CRDN_STTS_CD)
            .addObject("FIM046List", commonCodes.get("FIM046"))                // 감경 구분 코드(RDCT_SE_CD)
        ;
    }

    /**부과 대장 목록을 조회하여 반환한다.
     * {@link LevyService#getLevyList(LevyQuery)} 참고
     * @param req 부과 대장 조회 조건
     * @return jsonView
     * <pre><code> {
     *     "levyList": [부과 대장 목록]
     *     "levyStart": 부과 대장 목록 시작 인덱스
     *     "levyFetch": 한 번에 가져오는 부과 대장 목록 수
     *     "levyTotal": 조회 결과 찾은 전체 부과 대장 수
     * }</code></pre>
     */
    @Task
    @RequestMapping(name="부과 대장 목록 조회", value=METHOD_URL.getLevyList)
    public ModelAndView getLevyList(LevyQuery req) {
        if (!"xls".equals(req.getDownload())) {
            List<?> result = levyService.getLevyList(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 = levyService.getLevyList(req.setFetchSize(0));

            Map<String,Object> valueMap = new HashMap<String,Object>();
            valueMap.put("업무구분", format.of("TASK_SE_NM").style(center));
            valueMap.put("회계연도", format.of("FYR").style(center));
            valueMap.put("회계코드", format.of("ACNTG_SE_CD").style(center));
            valueMap.put("세목코드", format.of("TXITM_CD").style(center));
            valueMap.put("세목명", format.of("TXITM_NM").style(center));
            valueMap.put("부과번호", format.of("LEVY_NO").style(center));
            valueMap.put("분납순번", format.of("ISPY_SN").style(center));
            valueMap.put("부과구분", format.of("LEVY_SE_NM").style(center));
            valueMap.put("통합구분", format.of("UNTY_SE_NM").style(center));
            valueMap.put("감경구분", format.of("RDCT_SE_NM").style(center));
            valueMap.put("부과일자", FormatMaker.yyyy_mm_dd(format, "LEVY_YMD").style(dateYMD));
            valueMap.put("최초납기일자", FormatMaker.yyyy_mm_dd(format, "FRST_DUDT_YMD").style(dateYMD));
            valueMap.put("납기일자", FormatMaker.yyyy_mm_dd(format, "DUDT_YMD").style(dateYMD));
            valueMap.put("과태료금액", format.of("FFNLG_AMT").style(numeric));
            valueMap.put("부과본세", format.of("LEVY_PCPTAX").style(numeric));
            valueMap.put("부과가산금", format.of("LEVY_ADAMT").style(numeric));
            valueMap.put("분납이자", format.of("ISPY_INT").style(numeric));
            valueMap.put("수납본세", format.of("RCVMT_PCPTAX").style(numeric));
            valueMap.put("수납가산금", format.of("RCVMT_ADAMT").style(numeric));
            valueMap.put("감액본세", format.of("RDAMT_PCPTAX").style(numeric));
            valueMap.put("감액가산금", format.of("RDAMT_ADAMT").style(numeric));
            valueMap.put("최종금액", format.of("LAST_AMT").style(numeric));
            valueMap.put("과세물건", format.of("TXTN_THING"));
            valueMap.put("체납사유", format.of("NPMNT_RSN_NM"));
            valueMap.put("수납일자", FormatMaker.yyyy_mm_dd(format, "RCVMT_YMD").style(dateYMD));
            valueMap.put("압류일자", FormatMaker.yyyy_mm_dd(format, "SZR_YMD").style(dateYMD));
            valueMap.put("압류물건", format.of("SZR_THING"));
            valueMap.put("대체압류차량", format.of("RPM_SZR_VHRNO"));
            valueMap.put("압류해제일자", FormatMaker.yyyy_mm_dd(format, "SZR_RMV_YMD").style(dateYMD));
            valueMap.put("전자납부번호", format.of("EPAYNO_MASK"));
            valueMap.put("은행명", format.of("BANK_NM"));
            valueMap.put("가상계좌번호", format.of("VR_ACTNO").style(center));
            valueMap.put("은행명2", format.of("BANK_NM2"));
            valueMap.put("가상계좌번호2", format.of("VR_ACTNO2").style(center));
            valueMap.put("은행명3", format.of("BANK_NM3"));
            valueMap.put("가상계좌번호3", format.of("VR_ACTNO3").style(center));
            valueMap.put("단속일시", FormatMaker.yyyy_mm_dd_hh_mm_ss(format, "CRDN_YMD_TM").style(dateDT));
            valueMap.put("차량번호", format.of("VHRNO"));
            valueMap.put("법정동", format.of("CRDN_STDG_NM"));
            valueMap.put("단속장소", format.of("CRDN_PLC"));
            valueMap.put("위반항목", format.of("VLTN_ARTCL"));
            valueMap.put("단속원금", format.of("FFNLG_CRDN_AMT").style(numeric));
            valueMap.put("처리상태", format.of("CRDN_STTS_NM"));
            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("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"));
        }
    }
}