package cn.hmsoft.skill.enrol.service;

import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;

import cn.hmsoft.frame.constants.FrameStatus;
import cn.hmsoft.frame.exception.BusinessException;
import cn.hmsoft.frame.util.FrameAssertUtil;
import cn.hmsoft.helper.JsonHelper;
import cn.hmsoft.helper.LocalDateHelper;
import cn.hmsoft.helper.StringHelper;
import cn.hmsoft.log.LogHelper;
import cn.hmsoft.pay.data.model.PayBill;
import cn.hmsoft.skill.constants.StdLogType;
import cn.hmsoft.skill.constants.StdMateialType;
import cn.hmsoft.skill.data.dao.school.SchoolAspectDao;
import cn.hmsoft.skill.data.dao.school.SchoolRegDao;
import cn.hmsoft.skill.data.dao.std.StdEnrolDao;
import cn.hmsoft.skill.data.dao.std.StdLogDao;
import cn.hmsoft.skill.data.model.school.SchoolAspect;
import cn.hmsoft.skill.data.model.school.SchoolReg;
import cn.hmsoft.skill.data.model.std.StdEnrol;
import cn.hmsoft.skill.data.model.std.StdReg;
import cn.hmsoft.skill.helper.SkillMateialHelper;
import cn.hmsoft.skill.helper.WebServiceHelper;

@Service
public class EnrolStdEnrolService {

	@Autowired
	private StdEnrolDao daoEnrol;
	@Autowired
	private SchoolAspectDao daoAspect;
	@Autowired
	private SchoolRegDao daoSchool;
	@Autowired
	private StdLogDao daoLog;
	@Autowired
	private EnrolPayService serviceEnrol;

	public StdEnrol findByEnrolId(int enrol_id) {
		return this.daoEnrol.find(enrol_id);
	}
	
	public StdEnrol findById(int enrol_id) {
		return this.daoEnrol.findById(enrol_id);
	}

	public void save(StdReg std, StdEnrol enrol, boolean skip_time_check) {
		FrameAssertUtil.checkParam(enrol.getStd_id(), enrol.getAspect_id(), enrol.getSchool_id());
		// 判断是否已经报考
		Map<String, Object> e = this.daoEnrol.findEnrol(enrol.getStd_id(), enrol.getAspect_id());
		FrameAssertUtil.isNull(e, "该考生已经进行了报考，本类型考试禁止同一考生进行多次报考！");
		// 判断是否是越权报考
		SchoolAspect aspect = this.daoAspect.find(enrol.getAspect_id());
		SchoolReg school = this.daoSchool.find(enrol.getSchool_id());
		FrameAssertUtil.isEqual(aspect.getSchool_id(), enrol.getSchool_id(), "此学校未设置该专业！");
		// 判断是否超出报名时间
		if (!skip_time_check) {
			FrameAssertUtil.isNotNull(school, "未找到学校信息！");
			if (school.getEnrol_start_time() == null || school.getEnrol_start_time().isAfter(LocalDateTime.now()))
				throw new BusinessException("该考点暂未开放报考！请稍后重试");
			if (school.getEnrol_end_time() == null || school.getEnrol_end_time().isBefore(LocalDateTime.now()))
				throw new BusinessException("该考点报考已关闭！");
		}
		enrol.setEnrol_status(FrameStatus.Active.toString());
		enrol.setEnrol_time(LocalDateTime.now());
		enrol.setFee_amount(aspect.getFee_amount());
		this.daoEnrol.insert(enrol);
		this.daoLog.log(school.getSchool_id(), enrol.getStd_id(), StdLogType.Enrol, null, enrol.getEnrol_id() + "",
				enrol.getAspect_id() + "->" + aspect.getAspect_name(), enrol.getEnrol_time());

	}

	public List<StdEnrol> list(int std_id) {
		return this.daoEnrol.list("std_id", std_id);
	}

	public void cancel(int std_id, int enrol_id) {
		StdEnrol enrol = this.findByEnrolId(enrol_id);
		FrameAssertUtil.isNotNull(enrol, "未找到报考信息");
		FrameAssertUtil.isEqual(std_id, enrol.getStd_id(), "越权操作，请退出重新登录");
		FrameAssertUtil.isNotEqual(FrameStatus.Active.toString(), enrol.getPay_status(), "该报考信息已缴费确认，禁止进行取消操作！");

		SchoolAspect aspect = this.daoAspect.find(enrol.getAspect_id());
		this.daoEnrol.delete(enrol_id);
		this.daoLog.log(enrol.getSchool_id(), enrol.getStd_id(), StdLogType.Cancel, null, enrol.getEnrol_id() + "",
				enrol.getAspect_id() + "->" + aspect.getAspect_name(), LocalDateTime.now());

	}

	public StdEnrol checkPayStatus(StdReg std, int enrol_id) {
		StdEnrol enrol = this.findByEnrolId(enrol_id);
		if (enrol == null) {
			throw new BusinessException("未找到报考信息！");
		}
		FrameAssertUtil.isEqual(enrol.getStd_id(), std.getStd_id(), "越权使用系统，请退出重新登录！");
		if (FrameStatus.Active.toString().equals(enrol.getPay_status())) {
			throw new BusinessException("该报考已完成缴费！");
		}

		// 判断超时
		if (enrol.getPay_end_time() != null) {
			if (enrol.getPay_end_time().isBefore(LocalDateTime.now()))
				throw new BusinessException("已超过缴费时限，缴费通道关闭！");
		} else {
			// 从考点判断
			SchoolReg school = this.daoSchool.find(enrol.getSchool_id());
			if (school.getEnrol_end_time().isBefore(LocalDateTime.now()))
				throw new BusinessException("已超过缴费时限，缴费通道关闭！");

		}
		return enrol;
	}

	public StdEnrol checkPayStatus(int enrol_id) {
		StdEnrol enrol = this.findByEnrolId(enrol_id);
		if (enrol == null) {
			throw new BusinessException("未找到报考信息！");
		}
		StdReg std = this.daoAspect.find(StdReg.class, enrol.getStd_id());

		return checkPayStatus(std, enrol_id);
	}

	public void pay(int enrol_id, Integer bill_id) {
		StdEnrol enrol = this.daoEnrol.find(enrol_id);
		if (enrol != null && !FrameStatus.Active.toString().equals(enrol.getPay_status())) {
			enrol.setBill_id(bill_id);
			enrol.setPay_status(FrameStatus.Active.toString());
			enrol.setPay_time(LocalDateTime.now());
			this.daoEnrol.update(enrol);

			SchoolAspect aspect = this.daoAspect.find(enrol.getAspect_id());
			this.daoLog.log(enrol.getSchool_id(), enrol.getStd_id(),
					bill_id == null ? StdLogType.BatchPay : StdLogType.AspectPay, null, enrol.getEnrol_id() + "",
					enrol.getAspect_id() + "->" + aspect.getAspect_name(), enrol.getPay_time());
		}
	}
	
	public synchronized void stdSchoolMergePdf(String std_school_code, Integer school_id) throws Exception {
		String sql = "select e.* from std_reg r,std_enrol e where r.std_id=e.STD_ID and r.STD_PARAM1=? and e.school_id=? and ticket_num is not null order by exam_id";
		File dest = SkillMateialHelper.makeStdImageFile(StdMateialType.StdTicket, "T" + school_id + std_school_code + ".pdf");

		PdfDocument pdf = new PdfDocument(new PdfWriter(dest.getPath()));
		PdfMerger merger = new PdfMerger(pdf);
		for (StdEnrol e : daoAspect.listBySql(StdEnrol.class, sql, std_school_code, school_id)) {
			try {
				PdfDocument firstSourcePdf = new PdfDocument(new PdfReader(
						SkillMateialHelper.getStdImagePath(e.getTicket_file(), StdMateialType.StdTicket)));
				merger.merge(firstSourcePdf, 1, firstSourcePdf.getNumberOfPages());
				firstSourcePdf.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			}

		}
		pdf.close();
	}

	//襄阳-缴费初始化
	public void initPay(int enrol_id, String exam_type) {
		String url = "http://upay.hbxytc.cn:8088/bmapi/commonclass.asmx?WSDL";
		String bizXmlns = "xmlns:req=\"http://tempuri.org/\"";
		StdEnrol enrol = this.daoEnrol.find(enrol_id);
		StdReg std = daoEnrol.findBySql(StdReg.class, "select * from std_reg where std_id in (select std_id from std_enrol where enrol_id=?)", enrol_id);
		SchoolAspect aspect = this.daoAspect.findBySql("select * from school_aspect where aspect_id in (select aspect_id from std_enrol where enrol_id=?)", enrol_id);
		try {
			this.sendStdInfo(url, bizXmlns, std, aspect, exam_type);
			this.sendBasicPayData(url, bizXmlns, exam_type, std, enrol.getFee_amount());
		} catch(BusinessException e) {
			throw e;
		}
		
	}
	
	//襄阳-发送考生信息
	private void sendStdInfo(String url, String bizXmlns, StdReg std, SchoolAspect aspect, String exam_type) {
		StringBuilder body = new StringBuilder();
		String xh = std.getCert_id();
		body.append("<req:setxsxx>");
		body.append("<req:xh>" + xh + "</req:xh>");//学号
		body.append("<req:xm>" + std.getStd_name() + "</req:xm>");//姓名
		body.append("<req:xb>" + std.getStd_sex() + "</req:xb>");//性别
		body.append("<req:isls>0</req:isls>");//是否临时学号
		body.append("<req:rxnd>" + LocalDate.now().getYear() + "</req:rxnd>");//入校年度 如2020
		body.append("<req:lxnd>" + (LocalDate.now().getYear() + 5) + "</req:lxnd>");//离校年度
		body.append("<req:bmbh>99</req:bmbh>");//系部编号（后台先一次导入或编辑，测试99 待分配）
		body.append("<req:bjbh>" + LocalDate.now().getYear() + "9999" + "</req:bjbh>");//班级编号（后台先一次导入或编辑，测试20209999 待分配）
		body.append("<req:zybh>" + aspect.getAspect_id() + "</req:zybh>");//专业编号
		body.append("<req:xzbh>" + exam_type + "</req:xzbh>");//53-技能高考，52-单招
		body.append("<req:sfzh>" + std.getCert_id() + "</req:sfzh>");//身份证号
		body.append("<req:ksbh></req:ksbh>");//考试编号
		body.append("<req:jtzz></req:jtzz>");//家庭地址 
		body.append("<req:iszs>0</req:iszs>");//是否住宿（默认=0，不住，1=住）
		body.append("<req:xszt>5</req:xszt>");//学生状态(1=在学、2休学、3、退学、4、毕业、5其他 默认=1)
		body.append("<req:dh>" + std.getStd_mobile1() + "</req:dh>");//电话
		body.append("<req:yx></req:yx>");
		body.append("<req:tm>" + LocalDateHelper.formatLongNoSplit(LocalDateTime.now()) + "</req:tm>");//yyyyMMddHHmmss
		body.append("<req:sign>" + sign(xh) + "</req:sign>");//密文字符串另见技术文档
		body.append("</req:setxsxx>");
		String ret = WebServiceHelper.callWebService(url, bizXmlns, body.toString());
		if (StringHelper.isNotEmpty(ret)) {
			String json = ret.substring(ret.indexOf("<setxsxxResult>") + "<setxsxxResult>".length(), ret.indexOf("</setxsxxResult>"));
			Map<String, String> map = JsonHelper.toMap(json);
			if (map != null && map.get("returncode").equals("00000")) {
				//成功
				LogHelper.info("襄阳支付--设置考生信息成功!");
			} else {
				LogHelper.error(map.get("returnmsg"));
				throw new BusinessException(map.get("returnmsg"));
			}
		}
	}
	
	//襄阳-发送缴费标准
	private void sendBasicPayData(String url, String bizXmlns, String exam_type, StdReg std, Integer amt) {
		StringBuilder body = new StringBuilder();
		String xh = std.getCert_id();
		String amtStr = new BigDecimal(amt + "").divide(new BigDecimal("100")).toPlainString();
		body.append("<req:setxsysk>");
		body.append("<req:xh>" + xh + "</req:xh>");//学号
		body.append("<req:sfqjdm>" + LocalDate.now().getYear() + "</req:sfqjdm>");//收费期间代码 2020
		body.append("<req:sfxmdm>"+ exam_type +"</req:sfxmdm>");//收费项目代码
		body.append("<req:ysje>" + amtStr + "</req:ysje>");
		body.append("<req:tm>" + LocalDateHelper.formatLongNoSplit(LocalDateTime.now()) + "</req:tm>");//yyyyMMddHHmmss
		body.append("<req:sign>" + sign(xh) + "</req:sign>");//密文字符串另见技术文档
		body.append("</req:setxsysk>");
		String ret = WebServiceHelper.callWebService(url, bizXmlns, body.toString());
		if (StringHelper.isNotEmpty(ret)) {
			String json = ret.substring(ret.indexOf("<setxsyskResult>") + "<setxsyskResult>".length(), ret.indexOf("</setxsyskResult>"));
			Map<String, String> map = JsonHelper.toMap(json);
			if (map != null && map.get("returncode").equals("00000")) {
				//成功
				LogHelper.info("襄阳支付--设置缴费标准成功!");
			} else {
				LogHelper.error(map.get("returnmsg"));
				throw new BusinessException(map.get("returnmsg"));
			}
		}
	}
	
	//襄阳-加密
	public static String sign(String xh) {
		Map<String, String> signMap = new HashMap<String, String>();
		signMap.put("0", "!");
		signMap.put("9", "|");
		signMap.put("8", "{");
		signMap.put("7", "}");
		signMap.put("6", "[");
		signMap.put("5", "%");
		signMap.put("4", "^");
		signMap.put("3", "*");
		signMap.put("2", "/");
		signMap.put("1", "]");
		
		StringBuilder ret = new StringBuilder("XYZY");
		for (int i=0; i<xh.length(); i++) {
			ret.append(signMap.get(String.valueOf(xh.charAt(i))));
		}
		return ret.toString();
	}

	//襄阳支付检查
	public boolean xyCheck(int enrol_id) {
		String url = "http://upay.hbxytc.cn:8088/bmapi/commonclass.asmx?WSDL";
		String bizXmlns = "xmlns:req=\"http://tempuri.org/\"";
		StdReg std = daoEnrol.findBySql(StdReg.class, "select * from std_reg where std_id in (select std_id from std_enrol where enrol_id=?)", enrol_id);
		StringBuilder body = new StringBuilder();
		String xh = std.getCert_id();
		body.append("<req:getxsjfxx>");
		body.append("<req:xh>" + xh + "</req:xh>");//学号
		body.append("<req:sfqjdm>" + LocalDate.now().getYear() + "</req:sfqjdm>");//收费期间代码 2020
		body.append("<req:tm>" + LocalDateHelper.formatLongNoSplit(LocalDateTime.now()) + "</req:tm>");//yyyyMMddHHmmss
		body.append("<req:sign>" + sign(xh) + "</req:sign>");//密文字符串另见技术文档
		body.append("</req:getxsjfxx>");
		String ret = WebServiceHelper.callWebService(url, bizXmlns, body.toString());
		if (StringHelper.isNotEmpty(ret)) {
			String json = ret.substring(ret.indexOf("<getxsjfxxResult>") + "<getxsjfxxResult>".length(), ret.indexOf("</getxsjfxxResult>"));
			Map<String, String> map = JsonHelper.toMap(json);
			if (map != null && map.get("returncode").equals("00000")) {
				//成功
				String amt = map.get("SJS");
				if (Float.parseFloat(amt) > 0) {
					PayBill bill = new PayBill();
					bill.setBusiness_id(String.valueOf(enrol_id));
					this.serviceEnrol.pay(bill);
					return true;
				}
			} else {
				LogHelper.error(map.get("returnmsg"));
			}
		}
		return false;
	}
}
