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

import java.io.InputStream;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cokr.xit.base.code.service.bean.CodeBean;
import cokr.xit.base.file.FileInfo;
import cokr.xit.base.file.service.FileQuery;
import cokr.xit.base.file.service.bean.FileBean;
import cokr.xit.fims.cmmn.CmmnUtil;
import cokr.xit.fims.cmmn.service.bean.StngBean;
import cokr.xit.fims.crdn.Crdn;
import cokr.xit.fims.crdn.CrdnQuery;
import cokr.xit.fims.crdn.dao.CrdnInfoMapper;
import cokr.xit.fims.crdn.dao.CrdnInstMapper;
import cokr.xit.fims.crdn.dao.CrdnListMapper;
import cokr.xit.fims.crdn.dao.CrdnStngMapper;
import cokr.xit.fims.crdn.dao.CrdnUpdtMapper;
import cokr.xit.fims.crdn.dao.ImportMapper;
import cokr.xit.fims.crdn.service.CrdnService;
import cokr.xit.fims.cvlc.dao.CrdnCvlcptMapper;
import cokr.xit.fims.cvlc.service.bean.CrdnCvlcptMainBean;
import cokr.xit.fims.excl.LevyExcl;
import cokr.xit.fims.mngt.dao.TaskMapper;
import cokr.xit.fims.mngt.service.bean.TaskProcessor;
import cokr.xit.fims.payer.Payer;
import cokr.xit.fims.payer.service.bean.PayerBean;
import cokr.xit.fims.sprt.dao.TotalInfoMapper;
import cokr.xit.fims.sprt.service.bean.MediaBean;
import cokr.xit.foundation.component.AbstractServiceBean;
import cokr.xit.foundation.data.DataObject;
import cokr.xit.interfaces.lvis.v2406.LvisA01;

@Service("crdnService")
public class CrdnServiceBean extends AbstractServiceBean implements CrdnService {
	@Resource(name="crdnCvlcptMapper")
	private CrdnCvlcptMapper crdnCvlcptMapper;
	@Resource(name="crdnListMapper")
	private CrdnListMapper crdnListMapper;
	@Resource(name="crdnInstMapper")
	private CrdnInstMapper crdnInstMapper;
	@Resource(name="crdnUpdtMapper")
	private CrdnUpdtMapper crdnUpdtMapper;
	@Resource(name="crdnInfoMapper")
	private CrdnInfoMapper crdnInfoMapper;
	@Resource(name="crdnStngMapper")
	private CrdnStngMapper crdnStngMapper;
	@Resource(name="totalInfoMapper")
	private TotalInfoMapper totalInfoMapper;
	@Resource(name="taskMapper")
	private TaskMapper taskMapper;
	@Resource(name="fileBean")
	private FileBean fileBean;
	@Resource(name="codeBean")
	private CodeBean codeBean;
	@Resource(name="stngBean")
	private StngBean stngBean;
	@Resource(name="mediaBean")
	private MediaBean mediaBean;
	@Resource(name="importBean")
	private ImportBean importBean;
	@Resource(name="importMapper")
	private ImportMapper importMapper;
	@Resource(name="crdnStngBean")
	private CrdnStngBean crdnStngBean;
	@Resource(name="crdnCvlcptMainBean")
	private CrdnCvlcptMainBean crdnCvlcptMainBean;
	@Resource(name="crdnBean")
	private CrdnBean crdnBean;
	@Resource(name = "payerBean")
	private PayerBean payerBean;

	@Override
	public List<DataObject> getCrackdownList(CrdnQuery query) {
        String gridType = blankIfEmpty(query.getGridType());
		List<DataObject> dataObjectList = switch (gridType) {
	        case "tagInformationUndefinedData" -> {
	        	if (isEmpty(query.getOrderBy())) {
	    			if (isEmpty(query.getBy())) {
	    				query.setOrderBy("CRDN_ID DESC");
	    			} else {
	    				query.setOrderBy(CmmnUtil.convertCamelCaseToSnakeCase(query.getBy()));
	    			}
	    		}
	        	yield crdnListMapper.selectTagInformationUndefinedDataList(query);
	        }
	        case "photo" -> {
	        	if (isEmpty(query.getOrderBy())) {
	    			if (isEmpty(query.getBy())) {
	    				query.setOrderBy("VHRNO, CRDN_PLC, CRDN_ID DESC");
	    			} else {
	    				query.setOrderBy(CmmnUtil.convertCamelCaseToSnakeCase(query.getBy()));
	    			}
	    		}
	        	yield crdnListMapper.selectPhotoInspectionDataList(query);
	        }
	        case "sameVehicleMain" -> {
	        	if ("on".equals(query.getSchOnlySamePlace())) {
	        		query.setOrderBy("VHRNO, CRDN_STDG_NM");
	        	} else {
	        		query.setOrderBy("VHRNO");
	        	}
	        	yield crdnListMapper.selectSameVehicleMainList(query);
	        }
	        case "sameVehicleSub" -> crdnListMapper.selectSameVehicleSubList(query.setOrderBy("CRDN_ID"));
	        case "todayInsert" -> {
	        	query.setOrderBy("CRDN_ID DESC");
	        	yield crdnListMapper.selectTodayCrackdownList(query);
	        }
	        default -> {
	        	if (isEmpty(query.getOrderBy())) {
	    			if (isEmpty(query.getBy())) {
	    				query.setOrderBy("CRDN_ID DESC");
	    			} else {
	    				query.setOrderBy(CmmnUtil.convertCamelCaseToSnakeCase(query.getBy()));
	    			}
	    		}
	        	yield crdnListMapper.selectCrackdownList(query);
	        }
	    };

		switch (gridType) {
		case "tagInformationUndefinedData":
			dataObjectList.forEach(dataObject -> {
        		String state = dataObject.string("CRDN_STTS_CD");
        		int advntceAmt = toInt(dataObject.get("ADVNTCE_AMT"));
        		int ffnlgAmt = toInt(dataObject.get("FFNLG_AMT"));
        		int minusAmt = toInt(dataObject.get("MINUS_AMT"));
        		int adtnAmt = toInt(dataObject.get("ADTN_AMT"));
        		int rcvmtAmt = toInt(dataObject.get("RCVMT_AMT"));

        		dataObject.set("BLNC", crdnStngBean.getBalance(state,advntceAmt,ffnlgAmt,minusAmt,adtnAmt,rcvmtAmt));
			});
        	break;
		case "photo":
			dataObjectList.forEach(dataObject -> {
        		if (toInt(dataObject.get("ATCH_FILE_CNT")) < 1) {
        			dataObject
        				.set("INSP_RSLT", "사진없음")
        				.set("PRCS_MTHD", "해당자료에 사진을 등록하시기 바랍니다.");
        		} else if (toInt(dataObject.get("CRDN_CNT")) > 1) {
                	dataObject
                		.set("INSP_RSLT", "중복자료")
            			.set("PRCS_MTHD", TaskProcessor.get().getPrcsMthd(gridType));
                } else {
                	dataObject
                		.set("INSP_RSLT", "정상자료")
                		.set("PRCS_MTHD", "정상자료");
                }
			});
        	break;
        default: break;
		}

        return dataObjectList;
	}

	@Override
	public DataObject getCrackdownInfo(CrdnQuery query) {
		return crdnInfoMapper.selectCrdnInfo(query.getCrdnId());
	}

	@Override
	public int countCrdn(CrdnQuery crdnQuery) {
		return crdnListMapper.countCrdn(crdnQuery);
	}

	@Override
	public List<Crdn> getCrackdowns(List<String> crdnIds) {
		return crdnInfoMapper.selectCrdns(crdnIds);
	}

	@Override
	public Crdn getCrackdown(String crdnId) {
		return crdnInfoMapper.selectCrdn(crdnId);
	}

	@Override
	public String create(Map<String, Object> nonQueryRequest, Crdn crdn, List<FileInfo> fileInfoList) {
		return crdnBean.create(nonQueryRequest, crdn, fileInfoList) ? "[S]" : "[F]단속 자료 등록 중 오류가 발생하였습니다.";
	}

	@Override
	public String updateCrackdown(Crdn crdn) {
		Crdn loaded = getCrackdown(crdn.getCrdnId());
		if ("01,21".contains(loaded.getCrdnSttsCd())) {
			int vhclCpct = loaded.getVhclCpct();
			if (vhclCpct != crdn.getVhclCpct()) {
				LevyExcl excl = TaskProcessor.get().getLevyExcl(crdn);
				if (excl != null)
					crdnBean.create(excl);
			}
		}
		return crdnBean.updateCrackdown(crdn);
	}

	@Override
	public String updateVehicleOwners(InputStream upload, List<String> crdnIds) {
		List<Crdn> crdns = getCrackdowns(crdnIds);
		if (crdns.isEmpty())
			return "[F] 단속정보를 찾지 못했습니다.";

		LvisA01.A01Request req = new LvisA01.A01Request();
		Crdn first = crdns.get(0);
		req.setClient(TaskProcessor.get().getLvisConfig(first.getTaskSeCd()));

		try (InputStream input = upload) {
			List<DataObject> payerList = payerBean.getPayers(req, input);
			TaskProcessor taskProcessor = TaskProcessor.get();
			for (Crdn crdn: crdns) {
				String vhrno = crdn.getVhrno(),
					   crdnYmd = crdn.getCrdnYmd();
				for (DataObject info: payerList) {
					if (!vhrno.equals(info.get("vhrno"))
					 || !crdnYmd.equals(info.get("levy_stdde"))
					) continue;

					Payer payer = (Payer)info.get("payer");
					String rtpyrNo = payer != null ? payer.getRtpyrNo() : null;
					if (isEmpty(rtpyrNo) || rtpyrNo.contains("*")) // 납부자번호가 마스킹되어 있을 경우 제외
						continue;

					crdn.setInfo(payer);
					LevyExcl excl = taskProcessor.getLevyExcl(crdn);
					if (excl == null) {
						crdn.setCrdnSttsCd("21"); // 초기상태 -> 납부자등록
						crdnBean.updateCrackdownStatus(crdn);
					} else {
						crdn.setCrdnSttsCd(
							switch (excl.getLevyExclSeCd()) {
							case "1" -> "81";
							case "2" -> "83";
							default -> null;
							}
						);
						crdnBean.create(excl);
					}
					crdnBean.updateCrdnPayer(crdn);
				};
			}
			return "[S] 저장됐습니다.";
		} catch (Exception e) {
			throw runtimeException(e);
		}
	}

	@Override
	public String updateOverTimeInfo(String chgAmtSe, String crdnId) {
		DataObject crdnInfo = crdnInfoMapper.selectCrdnInfo(crdnId);
		Crdn crdn = new Crdn();
		crdn.setCrdnId(crdnInfo.string("CRDN_ID"));
		crdn.setTaskSeCd(crdnInfo.string("TASK_SE_CD"));
		crdn.setCrdnYmd(crdnInfo.string("CRDN_YMD"));
		crdn.setCrdnSpareaCd(crdnInfo.string("CRDN_SPAREA_CD"));
		crdn.setCrdnTm(crdnInfo.string("CRDN_TM"));
		crdn.setFfnlgCarmdlCd(crdnInfo.string("FFNLG_CARMDL_CD"));

		switch (chgAmtSe) {
		case "0":
			crdn.setOvtmYn("N");
			crdn.setOvtmPrttnYn("N");
			break;
		case "1":
			crdn.setOvtmYn("Y");
			crdn.setOvtmPrttnYn("N");
			break;
		case "2":
			crdn.setOvtmYn("Y");
			crdn.setOvtmPrttnYn("Y");
			break;
		default: throw new RuntimeException("2시간 초과 처리 중 오류가 발생하였습니다.");
		}

		if (crdnUpdtMapper.updateOverTimeInfo(crdn) != 1)
			return "[F]2시간초과여부 변경 중 오류가 발생하였습니다.";

		if (chgAmtSe.equals("0") || chgAmtSe.equals("1")) {
			int[] basicAmt = crdnStngBean.getBasicAmt(crdn);
			crdn.setFfnlgCrdnAmt(basicAmt[0]);
			crdn.setFfnlgAmt(basicAmt[0]);
			crdn.setAdvntceAmt(basicAmt[1]);
		} else if (chgAmtSe.equals("2")) {
			crdn.setFfnlgCrdnAmt(10000);
			crdn.setFfnlgAmt(10000);
			crdn.setAdvntceAmt(8000);
		}

		int affected = crdnUpdtMapper.updateCrdnAmt(crdn);
		if (affected != 1)
			return "[F]단속자료 금액 변경 중 오류가 발생하였습니다.";

		return "[S]";
	}

	@Override
	public String updateTagInfo(Crdn crdn) {
		return crdnUpdtMapper.updateTagInfo(crdn) == 1 ? "[S]" : "[F]";
	}

	@Override
	public String updateCrackdownStatus(Crdn crdn) {
		return crdnBean.updateCrackdownStatus(crdn);
	}

	@Override
	public String remove(String... crdnIds) {
		return crdnBean.remove(crdnIds) ? "[S]" : "[F]단속 자료 삭제 중 오류가 발생하였습니다.";
	}

	@Override
	public String removeCrackdown(Crdn crdn) {
		return crdnBean.removeCrackdown(crdn);
	}

	@Override
	public String removeCrackdownPayer(Crdn crdn) {
		return crdnBean.removeCrackdownPayer(crdn);
	}

	@Override
	public String removeEquipmentLinkFile(String workPath, String fileName) {
		return crdnBean.removeEquipmentLinkFile(workPath, fileName) ? "[S]" : "[F]장비연계파일 삭제 중 오류가 발생하였습니다.";
	}

	@Override
	public String changeCrdnImageFile(Crdn crdn, List<Map<String, Object>> processList) {
		int created = 0;
		int deleted = 0;
		boolean orderChange = false;

		int order = 0;
		for (Map<String, Object> process : processList) {
			switch ((String)process.get("process")) {
			case "insert": created += fileBean.create(List.of((FileInfo)process.get("obj"))); break;
			case "delete": deleted += fileBean.deleteByIDs((String)process.get("key")); break;
			case "order":
				mediaBean.reorder((String)process.get("key"), order++);
				orderChange = true;
				break;
			}
		}


		if (!orderChange) {
			// 단속 ID로 파일(TB_FILE) 정보 조회
			List<DataObject> infoFileList = fileBean.getFileList(
				new FileQuery().setInfoType(Crdn.INF_TYPE)
					.setInfoKeys(crdn.getCrdnId())
					.setOrderBy("SRT_ORD,FILE_ID")
			);

	        int size = infoFileList.size();
			if (size > 0) {
				String[] fileIDs = new String[size];

		        for (int i = 0; i < size; i++) {
		        	fileIDs[i] = infoFileList.get(i).string("FILE_ID");
		        }

		        fileBean.reorder(fileIDs);					// 첨부파일 재 정렬
			}
		}

		crdn.setAtchFileCnt(crdn.getAtchFileCnt() + created - deleted);
		boolean rtnScs = totalInfoMapper.updateCrdnAtchFileCnt(crdn);
		if (!rtnScs)
			throw new RuntimeException("단속 첨부 파일 갯수 수정에 실패하였습니다.");

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