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

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import cokr.xit.fims.cmmn.CmmnUtil;
import cokr.xit.fims.cmmn.CrdnSttsHstry;
import cokr.xit.fims.cmmn.service.bean.CrdnSttsHstryBean;
import cokr.xit.fims.levy.Levy;
import cokr.xit.fims.levy.LevyQuery;
import cokr.xit.fims.levy.dao.LevyMapper;
import cokr.xit.fims.mngt.service.bean.TaskProcessor;
import cokr.xit.foundation.UserInfo;
import cokr.xit.foundation.component.AbstractBean;
import cokr.xit.foundation.data.DataObject;

/**부과 대장 정보 관리 Bean
 *
 * <p>상세 설명:
 *
 * <pre>
 * ============ 변경 이력 ============
 * 2023-08-30	JoJH 최초 작성
 * ================================
 * </pre>
 */
@Component("levyBean")
public class LevyBean extends AbstractBean {
	/** 부과 대장 정보 DAO */
	@Resource(name = "levyMapper")
	private LevyMapper levyMapper;
	/** 단속 상태 이력 정보 Bean */
	@Resource(name = "crdnSttsHstryBean")
	private CrdnSttsHstryBean crdnSttsHstryBean;

	/**지정한 조건에 따라 감경부과 대상 목록을 조회하여 반환한다.
	 * @param req 부과 대장 조회 조건
	 * @return 부과 대장 목록
	 */
	public List<DataObject> getRdctLevyTrgtList(LevyQuery req) {
		// 삭제 여부 확인
		if (isEmpty(req.getDelYn()))
			req.setDelYn("N");
		// 정렬 확인
		if (isEmpty(req.getOrderBy()))
			req.setOrderBy(isEmpty(req.getBy()) ? "REG_DT" : CmmnUtil.convertCamelCaseToSnakeCase(req.getBy()));

		return levyMapper.selectRdctLevyTrgtList(req);
	}

	/**지정한 조건에 따라 부과 대장 목록을 조회하여 반환한다.
	 * @param req 부과 대장 조회 조건
	 * @return 부과 대장 목록
	 */
	public List<DataObject> getLevyList(LevyQuery req) {
		// 삭제 여부 확인
		if (isEmpty(req.getDelYn()))
			req.setDelYn("N");
		// 정렬 확인
		if (isEmpty(req.getOrderBy()))
			req.setOrderBy(isEmpty(req.getBy()) ? "REG_DT" : CmmnUtil.convertCamelCaseToSnakeCase(req.getBy()));

		return levyMapper.selectLevyList(req);
	}

	/**지정한 조건에 따라 부과 대장 객체들을 반환한다.
	 * @param req 부과 대장 조회 조건
	 * @return 부과 대장 객체 목록
	 */
	public List<Levy> getLevys(LevyQuery req) {
		// 삭제 여부 확인
		if (req.getDelYn() == null) {
			req.setDelYn("N");
		}
		if (req.getOrderBy() == null) {
			req.setOrderBy("L.LEVY_ID DESC");
		}

		return levyMapper.selectLevys(req);
	}

	/**지정한 부과 ID의 부과 대장 객체를 반환한다.<br />
	 * @param req 부과 대장 조회 조건
	 * @return 부과 대장 객체
	 */
	public DataObject getLevyInfo(LevyQuery req) {
		return levyMapper.selectLevyInfo(req);
	}

	/**지정한 회계연도의 부과 번호를 반환한다.<br />
	 * @param req 부과 대장 조회 조건
	 * @return 부과 대장 객체
	 */
	public String getMaxLevyNo(LevyQuery req) {
		return levyMapper.selectMaxLevyNo(req);
	}

	/**최근 2년내 지정한 조건의 부과 목록을 조회한다.
	 * @param req 조회 조건
	 * <ul><li>vhrno - 차량번호</li>
	 *     <li>vltnId - 위반ID</li>
	 *     <li>rtpyrId - 납부자 ID</li>
	 *     <li>date - 지정일자</li>
	 * </ul>
	 * @return 최근 2년내 지정한 조건의 부과 목록
	 */
	public List<DataObject> getPrevLevyList(LevyQuery req) {
		return levyMapper.selectPrevLevyList(req);
	}

	/**사전부과 대상 목록 정보를 부과 대장에 등록한다.
	 * @param levy 부과 대장
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createRdctLevyList(LevyQuery req) {
		// 최초 조회
		List<DataObject> trgtList = levyMapper.selectRdctLevyTrgtIds(req);
		// 조회 건수와 등록 대상 건수 확인
		if (!req.getTnocs().equals(Integer.toString(trgtList.size())))
			return "[F] 조회된 총 건수와 대상 건수가 다릅니다.";

		for (DataObject trgt: trgtList) {
			Levy levy = new Levy();
			levy.setSggCd(trgt.string("SGG_CD"));		// 시군구 코드
			levy.setTaskSeCd(trgt.string("TASK_SE_CD"));// 업무 구분 코드
			levy.setCrdnId(trgt.string("CRDN_ID"));		// 단속 ID
			levy.setLevyYmd(req.getLevyYmd());			// 부과 일자
			levy.setFrstDudtYmd(req.getDudtYmd());		// 최초 납기 일자
			levy.setDudtYmd(req.getDudtYmd());			// 납기 일자

			// 사전부과 정보를 부과 대장에 등록한다.
			String rtnMsg = createRdctLevy(levy);
			if (!rtnMsg.contains("[S]"))
				throw new RuntimeException(rtnMsg);
		}

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**사전부과 정보를 부과 대장에 등록한다.
	 * @param levy 부과 대장
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String createRdctLevy(Levy levy) {
		// 단속 정보
		DataObject crdnInfo = levyMapper.selectCrdn(levy.getCrdnId());
		// 전용차로위반, 주정차위반 과태료가 아니라면 오류.
		String taskSeCd = crdnInfo.string("TASK_SE_CD");
		String sggCd = levy.getSggCd();

		TaskProcessor taskProcessor = TaskProcessor.get();
		if (!taskProcessor.isPreImposable(taskSeCd))
			return "[F] 작업 중 " + crdnInfo.string("TASK_SE_NM") + " 업무는 사전부과를 할 수 없습니다.";
		if (!isEmpty(crdnInfo.string("LEVY_ID")))
			return "[F] 작업 중 이미 감경 부과된 자료가 있습니다.";
		if (toInt(crdnInfo.get("CRDN_STTS_CD")) > 31 )
			return "[F] 작업 중 단속 상태가 " + crdnInfo.string("CRDN_STTS_NM") + " 자료가 있습니다.";
		if (isEmpty(crdnInfo.string("RTPYR_ID")))
			return "[F] 작업 중 납부자 정보가 없는 자료가 있습니다.";

		// 사용자 정보

		UserInfo userInfo = currentUser();
		// 부과 정보
		levy.setInstCd(userInfo.getInstitute());							// 기관 코드
		levy.setDeptCd(userInfo.getDeptCode());								// 부서 코드
		levy.setSpclBizCd(crdnInfo.string("SPCL_BIZ_CD"));					// 특별회계 사업 코드
		levy.setFyr(levy.getLevyYmd().substring(0, 4));						// 회계연도
		levy.setAcntgSeCd(crdnInfo.string("ACNTG_SE_CD"));					// 회계 구분 코드
		levy.setTxitmCd(crdnInfo.string("TXITM_CD"));						// 세목 코드
		levy.setOperItemCd(crdnInfo.string("OPER_ITEM_CD"));				// 운영 항목 코드
		// MAX+1 부과 번호
		LevyQuery selectLevyNo = new LevyQuery();
		selectLevyNo.setSggCd(sggCd);
		selectLevyNo.setTaskSeCd(levy.getTaskSeCd());
		selectLevyNo.setFyr(levy.getFyr());
		selectLevyNo.setAcntgSeCd(crdnInfo.string("ACNTG_SE_CD"));
		selectLevyNo.setTxitmCd(crdnInfo.string("TXITM_CD"));
		selectLevyNo.setOperItemCd(crdnInfo.string("OPER_ITEM_CD"));

		levy.setLevyNo(levyMapper.selectMaxLevyNo(selectLevyNo));			// 부과 번호 (최종 부과번호+1 을 조회 한다.)
		levy.setIspySn("00");												// 분납 일련번호
		levy.setLevySeCd("02");												// 부과 구분 코드 FIM040
		levy.setUntySeCd("02");												// 통합 구분 코드 FIM072
        levy.setRdctSeCd(taskProcessor.getRdctSeCd(taskSeCd));         		// 감경 구분 코드
        levy.setFfnlgAmt(toInt(crdnInfo.get("FFNLG_AMT")));             	// 과태료 금액
        levy.setLevyPcptax(toInt(crdnInfo.get("ADVNTCE_AMT")));         	// 부과 본세
        levy.setLastAmt(toInt(crdnInfo.get("ADVNTCE_AMT")));            	// 최종 금액
        levy.setLevyAdamt(0);                                           	// 부과 가산금
        levy.setIspyInt(0);                                             	// 분납 이자
        levy.setRcvmtPcptax(0);                                         	// 수납 본세
        levy.setRcvmtAdamt(0);                                          	// 수납 가산금
        levy.setRdamtPcptax(0);                                         	// 감액 본세
        levy.setRdamtAdamt(0);                                          	// 감액 가산금
		levy.setTxtnThing(crdnInfo.string("VHRNO"));						// 과세 물건
		levy.setMngItem1(crdnInfo.string("CRDN_YMD_TM_MASK"));				// 관리 아이템1 - 위반일시
		levy.setMngItem2(crdnInfo.string("CRDN_STDG_NM") + " " + crdnInfo.string("CRDN_PLC"));	// 관리 아이템2 - 장소
		levy.setMngItem3(crdnInfo.string("VLTN_LAW_NM") + " " + crdnInfo.string("VLTN_LAW1") + " " + crdnInfo.string("VLTN_LAW2"));	// 관리 아이템3 - 법령
		levy.setMngItem4(crdnInfo.string("VLTN_ARTCL"));					// 관리 아이템4 - 위반항목
		levy.setMngItem5("");												// 관리 아이템5
		levy.setMngItem6(crdnInfo.string("SGG_CD") + crdnInfo.string("CRDN_ID"));	// 관리 아이템6 - 시군구코드 + 단속ID

		// 부과(TB_LEVY) 대장을 등록한다.
		int rtnNocs = levyMapper.insertLevy(levy);
		if (rtnNocs != 1)
			throw new RuntimeException("감경부과 대장 등록에 실패하였습니다.");

		// 단속상태이력(TB_CRDN_STTS_HSTRY)
		CrdnSttsHstry crdnSttsHstry = new CrdnSttsHstry();
		crdnSttsHstry.setCrdnId(crdnInfo.string("CRDN_ID"));				// 단속 ID
		crdnSttsHstry.setBfrSttsCd(crdnInfo.string("CRDN_STTS_CD"));		// 이전 단속 상태 코드
		crdnSttsHstry.setBfrSttsChgDt(crdnInfo.string("CRDN_STTS_CHG_DT"));	// 이전 단속 상태 변경 일시
		crdnSttsHstry.setCrdnSttsCd("23");									// 단속 상태 코드(FIM010) - 23: 사전부과
		crdnSttsHstry.setTaskDtlId(levy.getLevyId());						// 부과 ID

		boolean rtnScs = false;
		if (toInt(crdnInfo.get("CRDN_STTS_CD")) >= 1 && toInt(crdnInfo.get("CRDN_STTS_CD")) <= 22 ) {
			// 단속 상태 이력(TB_CRDN_STTS_HSTRY) 대장에 등록하고, 단속(TB_CRDN) 대장을 수정한다.
			rtnScs = crdnSttsHstryBean.createHstryUpdateCrdnSttsCd(crdnSttsHstry);
			if (!rtnScs)
				throw new RuntimeException("감경부과 등록 중 단속 대장의 단속상태 변경에 실패하였습니다.");	// 예외를 발생시켜서 DB Rollback
		} else {
			// 단속상태이력(TB_CRDN_STTS_HSTRY) 대장을 등록한다.
			rtnScs = crdnSttsHstryBean.create(crdnSttsHstry);
			if (!rtnScs)
				throw new RuntimeException("감경부과 등록 중 단속 대장의 단속상태 변경에 실패하였습니다.");	// 예외를 발생시켜서 DB Rollback
		}

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**감경부과 대장의 부과일자, 최초납기일자, 납기일자 정보를 수정한다.
	 * @param levy 부과 대장
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String updateRdctLevyYmd(Levy levy) {
		int rtnNocs = levyMapper.updateRdctLevyYmd(levy);
		if (rtnNocs != 1)
			throw new RuntimeException("부과 대장에 사전 감경부과 일자 정보 수정에 실패하였습니다.");	// 예외를 발생시켜서 DB Rollback

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**부과 대장에 수납 금액 정보를 수정한다.
	 * @param levy 부과 대장
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String updateLevyRcvmt(Levy levy) {
		int rtnNocs = levyMapper.updateLevyRcvmt(levy);
		if (rtnNocs != 1)
			throw new RuntimeException("부과 대장에 수납금액 정보 수정에 실패하였습니다.");	// 예외를 발생시켜서 DB Rollback

		return "[S] 작업이 정상 처리 되었습니다.";
	}

	/**부과 대장에 감액 금액 정보를 수정한다.
	 * @param levy 부과 대장
	 * @return 저장 여부
	 * <ul><li>저장됐으면 true</li>
	 *     <li>그렇지 않으면 false</li>
	 * </ul>
	 */
	public String updateLevyRdcamt(Levy levy) {
		int rtnNocs = levyMapper.updateLevyRdamt(levy);
		if (rtnNocs != 1)
			throw new RuntimeException("부과 대장에 수납금액 정보 수정에 실패하였습니다.");	// 예외를 발생시켜서 DB Rollback

		return "[S] 작업이 정상 처리 되었습니다.";
	}
}