package cokr.xit.fims.sndb.service.bean;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import cokr.xit.base.file.FileInfo;
import cokr.xit.base.file.service.bean.FileBean;
import cokr.xit.fims.base.FimsUser;
import cokr.xit.fims.cmmn.CmmnUtil;
import cokr.xit.fims.crdn.Crdn;
import cokr.xit.fims.crdn.CrdnQuery;
import cokr.xit.fims.crdn.dao.CrdnListMapper;
import cokr.xit.fims.mngt.dao.VltnMapper;
import cokr.xit.fims.mngt.service.bean.TaskProcessor;
import cokr.xit.fims.sndb.SndbQuery;
import cokr.xit.fims.sndb.Sndng;
import cokr.xit.fims.sndb.SndngDtl;
import cokr.xit.fims.sndb.dao.SndngDtlMapper;
import cokr.xit.fims.sndb.dao.SndngMapper;
import cokr.xit.foundation.component.AbstractBean;
import cokr.xit.foundation.data.DataObject;
import cokr.xit.interfaces.postplus.post.PostResponse;
import cokr.xit.interfaces.postplus.post.PostplusRequest;
import cokr.xit.interfaces.postplus.post.PstMsr;
import cokr.xit.interfaces.postplus.post.PstTemplate;
import cokr.xit.interfaces.postplus.post.service.PostplusService;

@Component("postplusBean")
public class PostplusBean extends AbstractBean {
    /** 파일 Bean */
    @Resource(name="fileBean")
    private FileBean fileBean;
    /** 위반 정보 정보 DAO */
    @Resource(name = "vltnMapper")
    private VltnMapper vltnMapper;
    @Resource(name = "crdnListMapper")
    private CrdnListMapper crdnListMapper;
    /** 발송 대장 정보 DAO */
    @Resource(name = "sndngMapper")
    private SndngMapper sndngMapper;
    /** 발송 상세 정보 DAO */
    @Resource(name = "sndngDtlMapper")
    private SndngDtlMapper sndngDtlMapper;
    @Resource(name = "postplusService")
    private PostplusService postplusService;

	public String requestProduction(Sndng sndng) {
        PstMsr.Master master = getMaster(sndng);

    	List<DataObject> sndngDtlList = sndngDtlMapper.selectSndngDtlList(
    		new SndbQuery()
    			.setSndngId(sndng.getSndngId())
    			.setDelYn("N")
    	);

    	List<String> crdnIDs = sndngDtlList.stream()
    		.map(row -> row.string("CRDN_ID"))
    		.toList();
    	String[] crdnIds = crdnIDs.toArray(new String[crdnIDs.size()]);
    	// 발송상세의 단속목록 조회
    	Map<String, DataObject> crdns = crdnListMapper.selectCrackdownList(new CrdnQuery().setCrdnIds(crdnIds)).stream()
    		.collect(Collectors.toMap(row -> row.string("CRDN_ID"), row -> row));
    	// 단속정보별 첨부파일 조회
    	Map<String, List<FileInfo>> fileInfos = fileBean.getFilesOf(Crdn.INF_TYPE, crdnIds).stream()
    		.collect(Collectors.groupingBy(FileInfo::getInfoKey));

        List<PstMsr.Detail> details = getDetails(sndngDtlList, crdns, fileInfos);

        // 제작신청 전송
        PstMsr pstMsr = new PstMsr()
        	.setMaster(master)
        	.setDetails(details)
        	.setAttachmentPaths(
        		fileInfos.values().stream()
        			.flatMap(infos -> infos.stream().map(FileInfo::getPath))
        			.toList()
        	);
        PostResponse presp = postplusService.requestProduction(pstMsr);
        if (!presp.success())
        	return "[F] " + presp.getRemark();

        // 발송 업데이트
        Sndng updtSndng = new Sndng();
        updtSndng.setConKey(master.getIntfID());  // 외부연계식별키
        updtSndng.setDivKb(master.getDelivery()); // 취급 구분
        updtSndng.setSndngSttsCd("01");           // 발송 상태 코드(FIM049) - 01 발송 대기
        updtSndng.setSndngId(sndng.getSndngId()); // 발송 ID
        sndngMapper.updateEPostSndng(updtSndng);  // 전자우편 발송 내역 수정

        // 발송상세 업데이트
        for (PstMsr.Detail detail: details) {
            SndngDtl sndngDtl = new SndngDtl();
            sndngDtl.setConKey(detail.getIntfID()); // 외부연계식별키
            sndngDtl.setRgNo(detail.getRegNo());    // 등기 번호
            sndngDtl.setSndngDtlSttsCd("03");       // 발송 상세 상태 코드(FIM050) - 03 발송
            sndngDtl.setSndngDtlId(detail.getSndngDtlId());

            sndngDtlMapper.updateSndngDtlEPost(sndngDtl);
        }

        return "[S] 우편발송 요청이 등록됐습니다";
	}

	private PstMsr.Master getMaster(Sndng sndng) {
        DataObject sndngInfo = sndngMapper.selectSndngInfo(
        	new SndbQuery()
        		.setSndngId(sndng.getSndngId())
        		.setDelYn("N")
        );

	    List<PstTemplate> templates = postplusService.getTemplates(
        	new PostplusRequest()
        		.setSggCd(sndng.getSggCd())
        		.setTaskSeCd(sndng.getTaskSeCd())
        		.setVltnId(sndngInfo.string("VLTN_ID"))
        		.setNoticeGb(sndngInfo.string("SNDNG_SE_CD"))
        );
        if (templates.isEmpty())
        	throw new RuntimeException("우편발송 기본설정을 찾지 못했습니다.");

        FimsUser user = (FimsUser)currentUser().getUser();

        return templates.get(0).setInfo(new PstMsr.Master())
        	.setSndngId(sndngInfo.string("SNDNG_ID"))
        	.setRecipientCount(sndngInfo.string("TNOCS"))
        	.setDelivery(sndng.getPostSndngSeCd())
        	.setSenderName(user.getName())
        	.setSenderSigungu(sndng.getSggCd())
        	.setSenderZipcode(user.getZipCode())
        	.setSenderAddress(user.getAddress())
        	.setSenderDetailAddress(user.getAddressDetail())
        	.setSenderDeptCd(user.getDeptCode())
        	.setSenderPhoneNo(user.getPhoneNo())
        	.setSenderEmail(user.getEmailAddress());
	}

	private List<PstMsr.Detail> getDetails(List<DataObject> sndngDtlList, Map<String, DataObject> crdns, Map<String, List<FileInfo>> fileInfos) {
		TaskProcessor taskProcessor = TaskProcessor.get();
        return sndngDtlList.stream()
			.map(dtlInfo -> {
				String crdnId = dtlInfo.string("CRDN_ID");
				DataObject crdn = crdns.get(crdnId);
				List<FileInfo> files = fileInfos.get(crdnId);

				PstMsr.Detail detail = new PstMsr.Detail()
					.setSndngDtlId(dtlInfo.string("SNDNG_DTL_ID"))     // 발송상세ID
					.setName(dtlInfo.string("RCPN_NM"))                // 이름
					.setZipcode(dtlInfo.string("RCPN_ZIP"))            // 우편번호
					.setAddress(dtlInfo.string("RCPN_ADDR"))           // 주소
					.setDetailAddress(dtlInfo.string("RCPN_DTL_ADDR")) // 상세주소
					.setPhoneNo(dtlInfo.string("RTPYR_TELNO"))         // 전화번호
					.setMobileNo(dtlInfo.string("RTPYR_MBL_TELNO"))    // 휴대전화번호
//					.setEmail(dtlInfo.string(""))	                   // 이메일주소

					.setRegGb(null)	// 등기구분
					.setRegNo(null)	// 등기번호
					.setRegNoDatetime(null)	// 등기번호 등록일시

					.setSerNo(null)	// 일련번호
					.setDeliveryCd(null)	// 발송코드

					.setBar1D(null) // 바코드 1D
					.setBar2D(null) // 바코드 2D
					.setNoticeNo(crdn.string("GOJI_NO")); // 고지서번호

				String sndngSeCd = dtlInfo.string("SNDNG_SE_CD");
				DataObject recevDoc = taskProcessor.getRecevDocCd(
	            	new DataObject()
	                	.set("taskSeCd", dtlInfo.get("TASK_SE_CD"))
	                	.set("taskSeNm", dtlInfo.get("TASK_SE_NM"))
	                	.set("infoSndngSeNm", dtlInfo.get("SNDNG_SE_NM"))
	                	.set("vltn", dtlInfo.get("VLTN_ARTCL"))
	                	.set("taxItem", "TODO: 세목")
	            );

				detail
					.setDocCd1(recevDoc.string("docCd1")) // 문서종류1
					.setDocCd2(recevDoc.string("docCd2")) // 문서종류2
					.setDocCd3(recevDoc.string("docCd3")) // 문서종류3
					.setDocCd4(recevDoc.string("docCd4")) // 문서종류4
					.setDocCd5(recevDoc.string("docCd5")) // 문서종류5

					.setSubject1(null) // 과목명1
					.setSubject2(null) // 과목명2
					.setSubject3(null) // 과목명3

					.setViolationDatetime(dtlInfo.string("CRDN_DT"))  // 위반일시
					.setViolationDong(dtlInfo.string("CRDN_STDG_NM")) // 위반동
					.setViolationLocation(dtlInfo.string("CRDN_PLC")) // 위반장소
					.setLegalBasis(crdn.string("VLTN_ARTCL"))         // 법조항
					.setPaymentNo1(null)	// 납부번호1
					.setPaymentNo2(null)	// 납부번호2
					.setEpaymentNo(dtlInfo.string("EPAYNO"))	// 전자납부번호
					.setVaccountNo(dtlInfo.string("BANK_NM") + " " + dtlInfo.string("VRACTNO")); // 가상계좌번호

				long pcptax = 0,         // 본세
	            	 adamt = 0,          // 가산금
	            	 lastAmt = 0,        // 최종 금액
	            	 dudtAftrPcptax = 0, // 납기후 본세
	            	 dudtAftrAdamt = 0,  // 납기후 가산금
	            	 dudtAftrAmt = 0;    // 납기후 합계 금액

	            // 계고장에는 최초 과태료 금액을 출력한다.
	            boolean warning = "01,11,12".contains(sndngSeCd); // 계고장 여부
				if (warning) {
	                pcptax = toLong(dtlInfo.get("FFNLG_AMT"));  // 본세 = 과태료 단속 금액
	                lastAmt = pcptax; // 합계 금액 = 과태료 단속 금액
	                adamt = dudtAftrPcptax = dudtAftrAdamt = dudtAftrAmt = 0;
	            } else {
	                pcptax = toLong(dtlInfo.get("PCPTAX"));    // 본세
	                adamt = toLong(dtlInfo.get("ADAMT"));      // 가산금
	                lastAmt = toLong(dtlInfo.get("LAST_AMT")); // 최종 금액

	                if (dtlInfo.string("SGG_CD").equals("50110")) {
	                    dudtAftrPcptax = dudtAftrAdamt = dudtAftrAmt = 0;
	                } else {
	                    dudtAftrAmt = toLong(dtlInfo.get("DUDT_AFTR_AMT")); // 납기후 금액
	                    if (dudtAftrAmt == 0) {
	                        dudtAftrPcptax = dudtAftrAdamt = dudtAftrAmt = 0;
	                    } else {
	                        dudtAftrPcptax = toLong(dtlInfo.get("PCPTAX")); // 납기후 본세
	                        if (dudtAftrAmt > dudtAftrPcptax) { // 납기후 금액이 본세보다 크다면..
	                            dudtAftrAdamt = toLong(dtlInfo.get("DUDT_AFTR_AMT")) - toLong(dtlInfo.get("PCPTAX"));
	                        } else if (dudtAftrAmt < dudtAftrPcptax) { // 납기후 금액이 본세보다 작다면 오류..
	                            throw new RuntimeException("우편통합 발송 작업중 납기후 금액이 본세보다 작은 자료가 발견되었습니다.");
	                        } else {
	                            dudtAftrAdamt = 0;
	                        }
	                    }
	                }
	            }

				detail.setFineAmt(toLong(dtlInfo.get("FFLNG_AMT")))       // 과태료
					.setPaymentAmt(lastAmt)                               // 납부금액
					.setDueDate(dtlInfo.string("DUDT_YMD_MASK"))          // 납부기한
					.setInDueDate(dtlInfo.string("DUDT_YMD_MASK"))        // 납기내기한
					.setInDueAmt(lastAmt)                                 // 납기내금액
					.setInDueAddedAmt(adamt)                              // 납기내가산금
					.setInDueChenapAmt(0)                                 // 납기내체납처분비
					.setOverdueDate(dtlInfo.string("DUDT_AFTR_YMD_MASK")) // 납기후기한
					.setOverdueAmt(dudtAftrAmt)                           // 납기후금액
					.setOverdueAddedAmt(dudtAftrAdamt)                    // 납기후가산금
					.setOverdueChenapAmt(0);                              // 납기후체납처분금

	            if (!warning) {         // 계고장이 아닐 경우
	                // TAX_NO = 부서코드(7) + 특별회계사업코드(4) + 회계연도(4) + 회계구분(2) + 세목코드(6) + 고지번호(6) + 분납순번(2)
	                String ocr0 = dtlInfo.string("TAX_NO") + CmmnUtil.getOcrVrfcCode("12357", dtlInfo.string("TAX_NO"), 31);
	                String ocr1 = CmmnUtil.getOcrband2(ocr0, dtlInfo.string("LEVY_SE_CD"), (int)lastAmt, dtlInfo.string("DUDT_YMD"));
					detail.setOcr0(ocr0)
						.setOcr1(ocr1)
						.setOcr2(CmmnUtil.getOcrband3(ocr1, (int)lastAmt, dtlInfo.string("DUDT_YMD"), (int)dudtAftrAmt));
	            }

				detail.setVhrno(dtlInfo.string("VHRNO"))      // 차량번호
					.setBirthday(dtlInfo.string("RCPN_BRDT")) // 생년월일
					.setPrintDate(null)   // 출력일자
					.setPrintYear(null)   // 출력년도
					.setPrintMonth(null)  // 출력월
					.setPrintDay(null)    // 출력일
					.setEvidenceNo(null); // 증거번호

				int fileCount = files.size();
				detail.setAttachmentCount(fileCount);	// 첨부파일수
				for (int i = 0; i < Math.min(fileCount, 4); ++i) {
					FileInfo fileInfo = files.get(i);
					String filename = FileInfo.name(fileInfo.getPath());
					switch (i) {
					case 0: detail.setAttachment1(filename); break;	// 첨부파일1
					case 1: detail.setAttachment2(filename); break;	// 첨부파일2
					case 2: detail.setAttachment3(filename); break;	// 첨부파일3
					case 3: detail.setAttachment4(filename); break;	// 첨부파일4
					default: break;
					}
				}

				return detail
					.setVariableTitle(null)	   // 가변제목
					.setVariableContent1(null) // 가변1
					.setVariableContent2(null) // 가변2
					.setVariableContent3(null) // 가변3
					.setVariableContent4(null) // 가변4

					.setVaccountNo2(dtlInfo.string("BANK_NM2") + " " + dtlInfo.string("VRACTNO2"))  // 가상계좌번호2
					.setVaccountNo3(dtlInfo.string("BANK_NM3") + " " + dtlInfo.string("VRACTNO3"))  // 가상계좌번호3
					.setVaccountNo4(dtlInfo.string("BANK_NM4") + " " + dtlInfo.string("VRACTNO4"))  // 가상계좌번호4
					.setVaccountNo5(dtlInfo.string("BANK_NM5") + " " + dtlInfo.string("VRACTNO5"))  // 가상계좌번호5
					.setVaccountNo6(dtlInfo.string("BANK_NM6") + " " + dtlInfo.string("VRACTNO6"))  // 가상계좌번호6
					.setVaccountNo7(dtlInfo.string("BANK_NM7") + " " + dtlInfo.string("VRACTNO7"))  // 가상계좌번호7
					.setVaccountNo8(dtlInfo.string("BANK_NM8") + " " + dtlInfo.string("VRACTNO8")); // 가상계좌번호8
			})
			.toList();
	}

	public void updateProductionStatus(String intfID) {
		postplusService.updateProductionStatus(null, List.of(intfID));
	}
}