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

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.stereotype.Component;

import cokr.xit.fims.crdn.Crdn;
import cokr.xit.fims.crdn.dao.ImportMapper;
import cokr.xit.fims.cvlc.CrdnCvlcpt;
import cokr.xit.fims.cvlc.dao.CrdnCvlcptMapper;
import cokr.xit.fims.payer.Payer;
import cokr.xit.fims.payer.service.bean.PayerBean;
import cokr.xit.foundation.AbstractComponent;
import cokr.xit.foundation.data.DataObject;
import cokr.xit.foundation.util.DateFormats;
import cokr.xit.interfaces.lvis.service.bean.VehicleInfoBean;
import cokr.xit.interfaces.lvis.service.reg.BasicInfoRequest;
import cokr.xit.interfaces.lvis.service.reg.BasicInfoResponse;
import cokr.xit.interfaces.smg.Petition;
import cokr.xit.interfaces.smg.dao.SmgMapper;

/**외부연계 파일에서 단속자료를 등록하는 Bean
 * @author mjkhan
 */
@Component("importBean")
public class ImportBean extends AbstractComponent {
	@Resource(name = "importMapper")
	private ImportMapper importMapper;
	@Resource(name = "smgMapper")
	private SmgMapper smgMapper;
	@Resource(name = "crdnCvlcptMapper")
	private CrdnCvlcptMapper cvlcptMapper;
	@Resource(name = "vehicleInfoBean")
	private VehicleInfoBean vehicleInfoBean;
	@Resource(name = "payerBean")
	private PayerBean payerBean;

	/**국민신문고 민원파일에서 단속자료를 추출하여 등록한다.
	 * @param interfaceSequences 외부연계 키
	 * @return 저장된 정보수
	 */
	public List<Crdn> createCrdns(List<Petition> petitions) {
		if (isEmpty(petitions)) return Collections.emptyList();

		Map<String, String>
			ssgs = getSSGs(petitions),
			carModels = importMapper.selectCarMdl();
		List<Crdn> crdns = create(petitions, ssgs);

		BiFunction<String, String, String> getCarModel = (vhctyAsortCd, mxmmLdg) -> {
			if (isEmpty(vhctyAsortCd)) return null;

			if ("3".equals(vhctyAsortCd)) {
				int weight = toInt(mxmmLdg);
				if (weight < 1) return null;

				vhctyAsortCd = weight <= 4000 ? "3-1" : "3-2";
			}
			return carModels.get(vhctyAsortCd);
		};
		setVehicleInfo(crdns, getCarModel);
		return crdns;
	}

	/**민원의 기관코드, 부서코드를 조건으로 시군구 코드를 조회한다.
	 * @param petitions 국민신문고 민원
	 * @return 기관코드, 부서코드별 시군구 코드("기관코드-부서코드", "시군구코드")
	 */
	private Map<String, String> getSSGs(List<Petition> petitions) {
		List<String>
			institutes = petitions.stream().map(petition -> petition.getPcdAncCodeV()).toList(),
			depts = petitions.stream().map(petition -> petition.getPcdDeptV()).toList();
		return importMapper.selectSggs(institutes, depts);
	}

	/**국민신문고 민원에서 단속자료를 생성하여 반환한다.
	 * @param petitions 국민신문고 민원
	 * @param sggs 시군구코드
	 * @return 단속자료 목록
	 */
	private List<Crdn> create(List<Petition> petitions, Map<String, String> sggs) {
		Petition.Violation violation = new Petition.Violation();
		DateFormats dateFormats = new DateFormats();

		return petitions.stream()
			.flatMap(petition -> {
				violation
					.setTitle(petition.getPetiTitleV())
					.setReason(petition.getPetiReasonL());

				List<Map<String, String>> vehicleNoDatetimes = violation.getVehicleNoDatetimes();

				//민원내용으로부터 차량번호와 단속일시를 추출하지 못했을 때
				if(vehicleNoDatetimes.size() == 0) {
					vehicleNoDatetimes.add(Map.of(
	                   	"datetime", petition.getPetiRegD().replaceAll("[-: ]", ""),
	                   	"vehicleNo", ""
	                ));
				}

				Map<String, List<Map<String, String>>> byVehicleNo = vehicleNoDatetimes.stream()
					.collect(Collectors.groupingBy(map -> map.get("vehicleNo"))); //차량번호별 단속정보

				List<String> vehicleNos = List.copyOf(byVehicleNo.keySet());

				DataObject codes = importMapper.selectViolationCodes(petition.getPetiTitleV() + " " + petition.getPetiReasonL());
				String
					taskCode = codes.string("TASK_CD"),
					violationCode = codes.string("VLTN_CD");

				return byVehicleNo.entrySet().stream()
					.map(entry -> {
						String vehicleNo = entry.getKey();
						boolean first = vehicleNos.indexOf(vehicleNo) < 1;
						Crdn crdn = new Crdn();

						String instDept = petition.getPcdAncCodeV() + "-" + petition.getPcdDeptV(),
							   sgg = sggs.get(instDept);
						crdn.setSggCd(sgg);
						crdn.setTaskSeCd(taskCode);

						crdn.setCrdnRegSeCd(first ? "02" : "04"); // 첫번째면 자동등록, 아니면 복사등록 (FIM026)
						crdn.setCrdnInptSeCd("14"); // 국민신문고 연계 (FIM003)

						crdn.setLinkTblNm("TB_ESB_INTERFACE");
						crdn.setLinkId(petition.getInterfaceSeqN());

						//crdn.setCrdnSeCd(null); // petition.getPetiPathGubunC() -> FIMS 코드로 변경

						crdn.setVhrno(vehicleNo); //차량번호
						List<Map<String, String>> datetimes = entry.getValue();
						String str = datetimes.get(datetimes.size() - 1).get("datetime"); //해당 차량의 마지막 날짜시간
						Date datetime = dateFormats.parse("yyyyMMddHHmmss", str);
						crdn.setCrdnYmd(dateFormats.format("yyyyMMdd", datetime)); //단속일자
						String time = dateFormats.format("HHmmss", datetime);
						crdn.setCrdnTm(time); //단속시간
						crdn.setCrdnBgngTm(time);

						String location = violation.getLocation(); //단속장소
						crdn.setCrdnStdgNm(violation.getDong(location));
						crdn.setCrdnPlc(location);
						crdn.setDtlCrdnPlc(null);

						crdn.setTeamId(null);
						crdn.setCrdnSpareaCd("00");
						crdn.setCrdnBgngTm(null);
						crdn.setCrdnEndTm(null);
						crdn.setCrdnSn(null);

						Map<String, String> coordinates = violation.getCoordinates();
						crdn.setGpsX(coordinates.get("latitude"));
						crdn.setGpsY(coordinates.get("longitude"));

						crdn.setTowngYn("N");
						crdn.setParkngPsbltyRsltCd("0");
						crdn.setOvtimeYn("N");
						crdn.setOpnnSbmsnYn("N");
						crdn.setCrdnSttsCd("01");

						crdn.setVltnCd(violationCode);

						crdn.setAtchFileCnt(petition.getAttachmentCount());
						return crdn;
					});
			})
			.toList();
	}

	/**단속 정보에 차량 정보를 설정한다.
	 * @param crdns
	 * @param basicInfoMap
	 */
	private void setVehicleInfo(List<Crdn> crdns, BiFunction<String, String, String> getCarModel) {
		List<BasicInfoRequest> reqs = crdns.stream()
			.filter(crdn -> !isEmpty(crdn.getVhrno()))
			.map(crdn -> {
				BasicInfoRequest req = new BasicInfoRequest();
				req.setLevy_stdde(crdn.getCrdnYmd());
				req.setVhrno(crdn.getVhrno());
				req.setSggCd(crdn.getSggCd());
				return req;
			}).toList();
		Map<String, Payer> payers = payerBean.getVehicleOwners(reqs).stream()
			.collect(Collectors.toMap(payer -> payer.getVhrno(), payer -> payer));

		crdns.forEach(crdn -> {
			Payer payer = payers.get(crdn.getVhrno());
			if (payer == null) return;

			BasicInfoResponse.BasicInfo vehicle = payer.getVehicleInfo();
			crdn.setSggCd(payer.getSggCd()); // 시군구 데이터 정리되면 지울 것
			crdn.setRtpyrId(payer.getRtpyrId());
			crdn.setVin(vehicle.getVin());
			crdn.setVhclNm(vehicle.getCnm());
			crdn.setVhclColor(vehicle.getColor_nm());
			crdn.setUseFuelCd(vehicle.getUse_fuel_code());
			crdn.setFfnlgCarmdlCd(getCarModel.apply(vehicle.getVhcty_asort_code(), vehicle.getMxmm_ldg()));
		});
	}

	public int createCvlcpts(List<Petition> petitions) {
		int affected = 0;
		UnaryOperator<String> parseDate = str -> {
			return str == null ? null :
				str.replace("-", "")
					.replace(":", "")
					.replace(" ", "");
		};
		Petition.Violation violation = new Petition.Violation();
		for (Petition petition: petitions) {
			violation.setTitle(petition.getPetiTitleV()).setReason(petition.getPetiReasonL());
			CrdnCvlcpt cvlcpt = new CrdnCvlcpt();

			cvlcpt.setCvlcptLinkId(petition.getInterfaceSeqN());
			cvlcpt.setDstrbncYn("N");
			String rcptYmd = parseDate.apply(petition.getAncRegD());
			if (rcptYmd != null && rcptYmd.length() >= 8)
				cvlcpt.setCvlcptRcptYmd(rcptYmd.substring(0, 8));

			String cvlcptAplySeCd = "";
			String petiAncCodeV = petition.getPetiAncCodeV();
			if(petiAncCodeV.equals("1741000")) cvlcptAplySeCd = "120"; //안전신문고
			else if(petiAncCodeV.equals("1140100")) cvlcptAplySeCd = "183"; //국민신문고
			else if(petiAncCodeV.equals("1320000")) cvlcptAplySeCd = "130"; //경찰청
			else cvlcptAplySeCd = "181"; //기타
			cvlcpt.setCvlcptAplySeCd(cvlcptAplySeCd);

			cvlcpt.setCvlcptAplyNo(petition.getPetiNoC());
			cvlcpt.setCvlcptRcptNo(petition.getCivilNoC());
			cvlcpt.setCvlcptListNo(null); //민원 목록 번호
			cvlcpt.setCvlcptAplcntNm(petition.getPeterNameV());
			cvlcpt.setCvlcptAplyDt(parseDate.apply(petition.getPetiRegD()));
			cvlcpt.setCvlcptAplyTtlNm(petition.getPetiTitleV());
			cvlcpt.setCvlcptAplyCn(petition.getPetiReasonL());
			cvlcpt.setCvlcptGist(petition.getCivilGistV());
			cvlcpt.setCvlcptPrcsPicNm(petition.getDutyIdV());
			cvlcpt.setCvlcptPrcsPrnmntDt(parseDate.apply(petition.getPetiEndD()));
			cvlcpt.setCvlcptPrcsCd(null);; // 민원 처리 코드
			cvlcpt.setCvlcptPrcsSumry(petition.getCivilAbstractL());
			cvlcpt.setCvlcptPrcsRsltCn(petition.getPcdRstContL());
			cvlcpt.setCvlcptPrcsCmptnDt(parseDate.apply(petition.getDoRegD()));
			cvlcpt.setCvlcptPrcsPic(petition.getDutyIdV());
			cvlcptMapper.insertCvlcpt(cvlcpt);
		}

		return affected;
	}
}