package com.cku.oa.appreciation.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import com.cku.oa.sys.code.SysCodeUtil;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import com.cku.core.ZAErrorCode;
import com.cku.core.ZAException;
import com.cku.oa.appreciation.dao.AppreciationApplyDao;
import com.cku.oa.appreciation.entity.AppreciationApply;
import com.cku.oa.appreciation.entity.AppreciationCertificate;
import com.cku.oa.appreciation.entity.AppreciationUser;
import com.cku.oa.sys.entity.user.CabSysUser;
import com.cku.oa.sys.entity.user.CabSysUserThirdRef;
import com.cku.oa.sys.entity.user.Member;
import com.cku.oa.sys.entity.user.MemberClubTypeEnum;
import com.cku.oa.sys.service.user.MemberService;
import com.cku.oa.sys.util.ValidateUtil;
import com.cku.oa.sys.util.ZtSmsUtil;
import com.cku.restful.v1.appreciation.model.RestAppreciationApply;
import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.service.CrudService;
import com.thinkgem.jeesite.common.utils.DateUtils;
import com.thinkgem.jeesite.common.utils.StringUtils;
import com.thinkgem.jeesite.common.utils.excel.ExportExcel;
import com.thinkgem.jeesite.common.utils.excel.ImportExcel;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 鉴赏课报名Service
 * 
 * @author zxy
 * @version 2022-02-15
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class AppreciationApplyService extends CrudService<AppreciationApplyDao, AppreciationApply> {

	@Autowired
	private MemberService memberService;

	public AppreciationApply get(String id) {
		return super.get(id);
	}

	public List<AppreciationApply> findList(AppreciationApply appreciationApply) {
		return super.findList(appreciationApply);
	}

	public List<AppreciationApply> findPaidByMobile(String mobile) {
		return dao.getPaidByMobile(mobile);
	}

	public Page<AppreciationApply> findPage(Page<AppreciationApply> page, AppreciationApply appreciationApply) {
		return super.findPage(page, appreciationApply);
	}

	@Transactional(readOnly = false)
	public void save(AppreciationApply appreciationApply) {
		super.save(appreciationApply);
	}

	@Transactional(readOnly = false)
	public void delete(AppreciationApply appreciationApply) {
		super.delete(appreciationApply);
	}
	
	@Transactional(readOnly = false)
	public void clean(AppreciationApply appreciationApply) {
		 dao.clean(appreciationApply);
	}

	public void export(AppreciationApply appreciationApply, HttpServletResponse response) throws IOException {
		List<AppreciationApply> list = findList(appreciationApply);
		// 课程ids
		Set<String> cIds = list.stream().filter(obj -> StringUtils.isNotEmpty(obj.getCourseId()))
				.map(obj -> obj.getCourseId()).collect(Collectors.toSet());
		// 查询课程报名数量
		List<AppreciationApply> applyNumList = new ArrayList<>();
		if (!CollectionUtils.isEmpty(cIds)) {
			applyNumList = this.getCoursesApplyNum(cIds);
		}

		for (AppreciationApply temp : list) {
			temp.setPaymentState(DictUtils.getDictLabels(temp.getPaymentState(), "user_payment_state", ""));
			temp.setApplyType(temp.getApplyType().equals("0") ? "正常" : "试听");
			// 课程状态
			for (AppreciationApply applyNum : applyNumList) {
				if (StringUtils.isNotEmpty(temp.getCourseId()) && temp.getCourseId().equals(applyNum.getCourseId())) {
					if (temp.getMaxNum() <= applyNum.getApplyNum()) {
						temp.setCourseState("1");
					}
				}
			}
			temp.setCourseState(DictUtils.getDictLabels(temp.getCourseState(), "appreciation_courses_state", ""));
		}
		new ExportExcel("报名信息", AppreciationApply.class, 1).setDataList(list).write(response, "报名信息表.xlsx").dispose();
	}

	@Transactional(readOnly = false)
	public synchronized String getMaxApplyCode() {
		Integer applyCode = dao.getMaxApplyCode();
		if (applyCode == null) {
			applyCode = 1;
		} else {
			applyCode++;
		}
		return String.format("%06d", applyCode);
	}

	@Transactional(readOnly = false)
	public void updateCourseId(AppreciationApply appreciationApply) throws Exception {
		dao.updateCourseId(appreciationApply);
		AppreciationApply obj = this.getCoursesApplyNum(appreciationApply.getCourseId());
		if (obj.getCourseState().equals("2") || obj.getMaxNum() < obj.getApplyNum()) {
			throw new ZAException(ZAErrorCode.ZA_ERROR, "该课程已结束或已达报名上限");
		}
	}

	@Transactional(readOnly = false)
	public void updateCourseIds(AppreciationApply appreciationApply) throws Exception {
		List<String> ids = Arrays.asList(appreciationApply.getId().split(","));
		dao.updateCourseIds(ids, appreciationApply.getCourseId());

		AppreciationApply obj = this.getCoursesApplyNum(appreciationApply.getCourseId());
		if (obj.getCourseState().equals("2") || obj.getMaxNum() < obj.getApplyNum()) {
			throw new ZAException(ZAErrorCode.ZA_ERROR, "该课程已结束或已达报名上限");
		}
	}

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void importMember(MultipartFile file)
			throws InvalidFormatException, IOException, InstantiationException, IllegalAccessException {
		ImportExcel ei = new ImportExcel(file, 0, 0);
		List<AppreciationApply> list = ei.getDataList(AppreciationApply.class);

		boolean error = false;
		StrBuilder strBuilder = new StrBuilder();
		int i = 2;
		for (AppreciationApply apply : list) {
			if (StringUtils.isEmpty(apply.getShopName()) && StringUtils.isEmpty(apply.getMobile())
					&& StringUtils.isEmpty(apply.getMemberName()) && StringUtils.isEmpty(apply.getProvince())
					&& StringUtils.isEmpty(apply.getCity()) && StringUtils.isEmpty(apply.getArea())) {
				i++;
				continue;
			}

			if (StringUtils.isEmpty(apply.getShopName())) {
				error = recordError(strBuilder, "第" + i + "行，门店名称不能为空");
			}

			if (StringUtils.isEmpty(apply.getMemberName())) {
				error = recordError(strBuilder, "第" + i + "行，姓名不能为空");
			}

			if (StringUtils.isEmpty(apply.getMobile())) {
				error = recordError(strBuilder, "第" + i + "行，手机号不能为空");
			}

			if (!ValidateUtil.phoneMobile(apply.getMobile())) {
				error = recordError(strBuilder, "第" + i + "行，手机号格式错误");
			}

			if (StringUtils.isEmpty(apply.getProvince())) {
				error = recordError(strBuilder, "第" + i + "行，省不能为空");
			}

			if (StringUtils.isEmpty(apply.getCity())) {
				error = recordError(strBuilder, "第" + i + "行，市不能为空");
			}

			if (StringUtils.isEmpty(apply.getArea())) {
				error = recordError(strBuilder, "第" + i + "行，区不能为空");
			}

			if (StringUtils.isEmpty(apply.getApplyChannel())) {
				error = recordError(strBuilder, "第" + i + "行，渠道名称不能为空");
			}

			if (StringUtils.isEmpty(apply.getPaymentState())) {
				error = recordError(strBuilder, "第" + i + "行，缴费状态不能为空");
			}

			if (StringUtils.isEmpty(apply.getApplyType())) {
				error = recordError(strBuilder, "第" + i + "行，缴费类型不能为空");
			}

			if (!error) {
				Member member = null;
				try {
					member = this.createMemberWithAppreciation(initMember(apply));
				} catch (Exception e) {
					error = recordError(strBuilder, "第" + i + "行，" + e.getMessage());
				}
				apply.setApplyCode(this.getMaxApplyCode());
				apply.setPaymentState("2");
				apply.setApplyType(apply.getApplyType().equals("正式") ? "0" : "1");
				apply.setMemberCode(member.getMemberCode());
				this.save(apply);
			}
			i++;
		}
		if (error) {
			throw new ZAException(ZAErrorCode.ZA_ERROR, strBuilder.toString());
		}
	}

	private boolean recordError(StrBuilder strBuilder, String msg) {
		strBuilder.append(msg).append("##");
		return true;
	}

	private RestAppreciationApply initMember(AppreciationApply apply) {
		RestAppreciationApply restAppreciationApply = new RestAppreciationApply();
		restAppreciationApply.setRealName(apply.getMemberName());
		restAppreciationApply.setMobile(apply.getMobile());
		restAppreciationApply.setProvince(apply.getProvince());
		restAppreciationApply.setCity(apply.getCity());
		restAppreciationApply.setArea(apply.getArea());
		return restAppreciationApply;
	}

	public List<AppreciationApply> getCoursesApplyNum(Set<String> ids) {
		return dao.getCoursesApplyNum(ids);
	}

	public AppreciationApply getCoursesApplyNum(String id) {
		return dao.getCoursesApplyNumById(id);
	}

	@Autowired
	private RedissonClient redissonClient;

	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public Member createMemberWithAppreciation(RestAppreciationApply appreciationApply) {
		// 1、验证手机号是否正确
		if (!ValidateUtil.Mobile(appreciationApply.getMobile())) {
			throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "手机号格式不正确");
		}
		RLock rLock = null;
		Member member = null;
		try {
			log.info("=====================创建鉴赏会员开始=====================" + DateUtils.formatDateTime(new Date()));
			rLock = redissonClient.getFairLock(appreciationApply.getMobile());
			// 活锁避免死锁
			rLock.lock(5, TimeUnit.MINUTES);
			// 2、验证手机号是否存在
			CabSysUser cabUser = memberService.getByLoginMobile(appreciationApply.getMobile());
			List<AppreciationUser> appreciationUserList = null;
			if (Objects.isNull(cabUser)) {
				appreciationUserList = dao.getByMobileWithMember(appreciationApply.getMobile());
				if (!CollectionUtils.isEmpty(appreciationUserList) && appreciationUserList.stream()
						.collect(Collectors.groupingBy(AppreciationUser::getMemberCode)).size() > 1) {
					throw new ZAException(ZAErrorCode.ZA_VALID_FAILED, "当前手机账号关联多个会员信息，暂无法报名，请联系客服处理，致电400-660-7000！");
				}
			}
			// （1）如已存在且会员姓名与当前报名人姓名相同，则不创建会员，如不相同则抛出异常
			if (Objects.nonNull(cabUser)) {
				// 根据登录信息查询相应会员信息
				List<CabSysUserThirdRef> refList = memberService.findByCabUserId(cabUser.getId());
				// 如CKU身份存在，则有优先使用CKU身份
				CabSysUserThirdRef ckuRef = refList.stream()
						.filter(r -> r.getThirdType().equals(MemberClubTypeEnum.CKU.code())).findAny().orElse(null);
				// 其次使用MC
				if (Objects.isNull(ckuRef)) {
					ckuRef = refList.stream().filter(r -> r.getThirdType().equals(MemberClubTypeEnum.CKUMC.code()))
							.findAny().orElse(null);
				}
				// 最终使用DC
				if (Objects.isNull(ckuRef)) {
					ckuRef = refList.stream().filter(r -> r.getThirdType().equals(MemberClubTypeEnum.CKUDC.code()))
							.findAny().orElse(null);
				}
				member = memberService.getByUserId(ckuRef.getThirdId());
			}
			// （2）如果手机号不存在，则创建未实名认证的会员,并创建登录信息
			else if (!CollectionUtils.isEmpty(appreciationUserList)) {
				member = memberService.getByMemberCode(appreciationUserList.stream().findAny().get().getMemberCode());
			} else {
				// 创建 member
				member = new Member();
				member.setName(appreciationApply.getRealName());
				member.setMobile(appreciationApply.getMobile());
				member.setProvince(appreciationApply.getProvince());
				member.setCity(appreciationApply.getCity());
				member.setArea(appreciationApply.getArea());
				member.setStreet(appreciationApply.getStreet());
				member = memberService.saveUnauthorizedMember(member);
				return member;
			}
		} catch (Exception e) {
			log.error("创建鉴赏会员失败：", e);
			throw new ZAException(ZAErrorCode.ZA_ERROR, "查询鉴赏会员失败");
		} finally {
			if (Objects.nonNull(rLock)) {
				rLock.unlock();
				log.info("=====================锁结束=====================" + DateUtils.formatDateTime(new Date()));
			}
		}
		return member;
	}

	public void sendAppreciationApplySMS(String businessIds) {
		AppreciationApply apply = get(businessIds);
		if(apply==null || StringUtils.isBlank(apply.getMobile())) {
			log.error("鉴赏课报名"+businessIds+"没有记录或者电话号码！");
			return;
		}
		if (!ZtSmsUtil.validateSmsWhiteList(apply.getMobile())) {
			logger.debug("短信发送失败，开发模式不能发送短信");
			return;
		}
		ZtSmsUtil.sendNote("报名已成功，工作人员将通过电话/短信方式为您提供开课通知，请留意接收。客服热线 400-660-7000。", apply.getMobile());
	}

	public List<AppreciationCertificate> findListByMemberCodeOrCertificateCode(String memberCode,String certificateCode) {
		return dao.getByMemberCodeOrCertificateCode(memberCode,certificateCode);
	}

	public Integer countByMemberCode(String memberCode) {
		return dao.countByMemberCode(memberCode);
	}

	/**
	 * 根据课程生成证书号
	 * @author yuanshuai
	 * @date 2022/3/2 15:46
	 */
	public void createCertificateCodeByCourses(String coursesId) {
		AppreciationApply search = new AppreciationApply();
		search.setCourseId(coursesId);
		search.setPaymentState("2");
		List<AppreciationApply> applyList = findList(search);
		Date now = new Date();
		applyList.forEach(apply -> {
			//生成证书号
			apply.setCertificateCode(SysCodeUtil.getAppreciationCertificateCode());
			apply.setIssueDate(now);
			dao.updateCertificate(apply);
		});
	}
}
