package com.yeejoin.amos.boot.module.common.biz.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.module.common.api.dto.CompanyPerson;
import com.yeejoin.amos.boot.module.common.api.dto.DutyCarDto;
import com.yeejoin.amos.boot.module.common.api.dto.DutyPersonDto;
import com.yeejoin.amos.boot.module.common.api.dto.DutyPersonShiftDto;
import com.yeejoin.amos.boot.module.common.api.dto.DutyShiftDto;
import com.yeejoin.amos.boot.module.common.api.entity.DutyPersonShift;
import com.yeejoin.amos.boot.module.common.api.entity.DutyShift;
import com.yeejoin.amos.boot.module.common.api.entity.DynamicFormColumn;
import com.yeejoin.amos.boot.module.common.api.entity.DynamicFormInstance;
import com.yeejoin.amos.boot.module.common.api.entity.OrgUsr;
import com.yeejoin.amos.boot.module.common.api.enums.DutyViewTypeEnum;
import com.yeejoin.amos.boot.module.common.api.service.IDutyCommonService;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author DELL
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DutyCommonServiceImpl implements IDutyCommonService {

	@Autowired
	DynamicFormColumnServiceImpl dynamicFormColumnService;

	@Autowired
	DynamicFormInstanceServiceImpl dynamicFormInstanceService;

	@Autowired
	DutyPersonShiftServiceImpl dutyPersonShiftService;

	@Autowired
	Sequence sequence;

	@Autowired
	HttpServletRequest request;

	@Autowired
	DutyShiftServiceImpl dutyShiftService;

	@Autowired
	OrgUsrServiceImpl orgUsrService;

	/**
	 * 每天单个班次执勤人数全部小于等于3人
	 */
	final int LIMIT_PERSON_NUMBER = 3;

	/**
	 * 班次小于等于2
	 */
	final int LIMIT_SHIFT_NUMBER = 2;

	@Override
	public IPage<Map<String, Object>> pageList(int current, int size, String beginDate, String endDate)
			throws ParseException {
		// 1.已column为准 进行返回
		String groupCode = this.getGroupCode();
		IPage<Map<String, Object>> iPage = dynamicFormInstanceService.pageList(current, size, groupCode);
		for (Map<String, Object> m : iPage.getRecords()) {
			this.fillDutyShiftData(beginDate, endDate, m);
		}
		return iPage;
	}

	private void fillDutyShiftData(String beginDate, String endDate, Map<String, Object> m) throws ParseException {
		// 获取值班的实例id
		String instanceId = m.get("instanceId").toString();
		// 根据appkey 获取未删除的值班班次
		List<DutyShift> dutyShifts = dutyShiftService.list(new LambdaQueryWrapper<DutyShift>()
				.eq(BaseEntity::getIsDelete, false).eq(DutyShift::getAppKey, RequestContext.getAppKey()));
		// 根据id 保存成key -value
		Map<Long, DutyShift> keyNameMap = dutyShifts.stream()
				.collect(Collectors.toMap(BaseEntity::getSequenceNbr, Function.identity()));
		// 根据时间 查询值班关系表

		// BUG 2806 获取月份第一天和最后一天  2021-09-09 by kongfm
			if(beginDate != null ) {
			Calendar c = Calendar.getInstance();
			c.setTime(DateUtils.longStr2Date(beginDate));
			c.set(Calendar.DAY_OF_MONTH, 1);
			c.set(Calendar.HOUR_OF_DAY,0);
			c.set(Calendar.MINUTE,0);
			c.set(Calendar.SECOND,0);
			beginDate = DateUtils.date2LongStr(c.getTime());
		}
		if(endDate != null ) {
			Calendar c = Calendar.getInstance();
			c.setTime(DateUtils.longStr2Date(beginDate));
			c.add(Calendar.MONTH, 1);
			c.set(Calendar.DAY_OF_MONTH, 1);
			c.add(Calendar.DATE, -1);
			c.set(Calendar.HOUR_OF_DAY,23);
			c.set(Calendar.MINUTE,59);
			c.set(Calendar.SECOND,59);
			endDate = DateUtils.date2LongStr(c.getTime());
		}
		List<DutyPersonShiftDto> personShiftList = dutyPersonShiftService
				.list(new LambdaQueryWrapper<DutyPersonShift>().eq(DutyPersonShift::getInstanceId, instanceId)
						.ge(beginDate != null, DutyPersonShift::getDutyDate, beginDate)
						.le(endDate != null, DutyPersonShift::getDutyDate, endDate))
				.stream().map(e -> {
					// 值班关系查询到以后 重新封装
					DutyPersonShiftDto dto = new DutyPersonShiftDto();
					Bean.copyExistPropertis(e, dto);
					// 没值班信息，默认休
					DutyShift dutyShift = keyNameMap.get(e.getShiftId());
					dto.setShiftName(dutyShift != null ? dutyShift.getName() : "休");
					dto.setColor(dutyShift != null ? dutyShift.getColor() : "");
					return dto;
				}).collect(Collectors.toList());
		m.put("dutyShift", personShiftList);
	}

	@Override
	public List<Map<String, Object>> statisticsDay(String beginDate, String endDate) throws ParseException {
		DutyViewTypeEnum viewTypeEnum = this.inferView(beginDate, endDate, RequestContext.getAppKey());
		List<Map<String, Object>> rangeDate = dutyPersonShiftService.getBaseMapper().genRangeDate(beginDate, endDate);
		return rangeDate.stream().map(p -> {
			Map<String, Object> result = new LinkedHashMap<>();
			result.put("key", p.get("date"));
			result.put("viewType", viewTypeEnum.getCode());
			result.put("data", this.buildViewData(viewTypeEnum, p.get("date").toString(), RequestContext.getAppKey()));
			return result;
		}).collect(Collectors.toList());
	}

	private Object buildViewData(DutyViewTypeEnum viewTypeEnum, String dutyDate, String appKey) {
		List<Map<String, Object>> result = new ArrayList<>();
		switch (viewTypeEnum) {
		case BANK:
			result = dutyPersonShiftService.getBaseMapper().bankViewData(dutyDate, appKey, this.getGroupCode());
			break;
		case STATION:
			result = dutyPersonShiftService.getBaseMapper().stationViewData(dutyDate, appKey, this.getGroupCode());
			break;
		default:
			break;
		}
		return result;
	}

	private DutyViewTypeEnum inferView(String beginDate, String endDate, String appKey) {
		Map<String, Long> result = dutyPersonShiftService.getBaseMapper().calMaxPersonAndShiftNum(beginDate, endDate,
				appKey, this.getGroupCode());
		// 计算班次最大执勤人数，时间区间内
		Long maxDutyPersonNumDay = result.get("maxDutyPersonNumDay");
		// 计算天的最大班次数量，时间区间内
		Long maxShiftNumDay = result.get("maxShiftNumDay");
		if (maxDutyPersonNumDay <= LIMIT_PERSON_NUMBER && maxShiftNumDay <= LIMIT_SHIFT_NUMBER) {
			return DutyViewTypeEnum.BANK;
		} else {
			return DutyViewTypeEnum.STATION;
		}
	}

	@Override
	public List<Map<String, Object>> list(Long teamId, String beginDate, String endDate) throws ParseException {
		// 1.已column为准 进行返回
		String groupCode = this.getGroupCode();
		// 动态表单查询所有值班信息
		List<Map<String, Object>> list = dynamicFormInstanceService.listAll(groupCode);
		
		// 2.组织值班数据
		for (Map<String, Object> map : list) {
			this.fillDutyShiftData(beginDate, endDate, map);
		}
		/*bug2472 添加根据部门id筛选数据的方法  陈浩 2021-08-21 开始	*/
		if(teamId!=null && teamId.intValue()!=0) {
			List<OrgUsr> orgUsrList = orgUsrService.getPersonListByParentId(teamId);
			List<Map<String, Object>>  resultList= new ArrayList<Map<String, Object>>();
			list.stream().forEach(i->{
				orgUsrList.forEach(m->{
					if(i.get("userId").toString().equals(m.getSequenceNbr().longValue()+"")) {
						resultList.add(i);
					}
				});
			});
			return resultList;
		}
		/*bug2472 添加根据部门id筛选数据的方法  陈浩 2021-08-21 结束	*/
		return list;
	}

	@Override
	public String getGroupCode() {
		return null;
	}

	@Override
	public List downloadList(String beginDate, String endDate) throws ParseException {
		List<Map<String, Object>> maps = this.list(null,beginDate, endDate);
		JSONArray jsonArray = new JSONArray();
		jsonArray.addAll(maps);
		List<?> list = new ArrayList<>();
		String groupCode = this.getGroupCode();
		String fileName;
		if ("dutyCar".equals(groupCode)) {
			list = jsonArray.toJavaList(DutyCarDto.class);
		} else {
			list = jsonArray.toJavaList(DutyPersonDto.class);
		}
		return list;
	}

	@Override
	public void saveImportData(List<Map<String, Object>> dataList) {
		List<DynamicFormInstance> formInstanceList = new ArrayList<>();
		Set<DutyPersonShift> dutyPersonShifts = new HashSet<>();
		dataList.forEach(d -> {
			// TODO： 业务唯一索引，用户id
			String userId = d.get("userId").toString();
			List<DynamicFormInstance> instances = dynamicFormInstanceService
					.list(new LambdaQueryWrapper<DynamicFormInstance>().eq(DynamicFormInstance::getFieldCode, "userId")
							.eq(DynamicFormInstance::getFieldValue, userId)
							.eq(DynamicFormInstance::getGroupCode, this.getGroupCode()));
			Long instanceId = null;
			List<DynamicFormColumn> columns = dynamicFormColumnService.list(new LambdaQueryWrapper<DynamicFormColumn>()
					.eq(DynamicFormColumn::getGroupCode, this.getGroupCode()));
			// 1.组装动态表单数据
			if (!instances.isEmpty()) {
				// 0.定位instanceId，准备进行更新操作
				instanceId = instances.get(0).getInstanceId();
				// 1.查询已有数据
				List<DynamicFormInstance> instancesInDb = dynamicFormInstanceService
						.list(new LambdaQueryWrapper<DynamicFormInstance>().eq(DynamicFormInstance::getInstanceId,
								instanceId));
				// 2.list 转 map
				Map<Object, DynamicFormInstance> instanceMap = Bean.listToMap(instancesInDb, "fieldCode",
						DynamicFormInstance.class);
				// 3.待更新数据组装，待批量入库
				this.updateFormValue(formInstanceList, d, instanceId, columns, instanceMap);
			} else {
				// 0.新数据，生成id
				instanceId = sequence.nextId();
				Long finalInstanceId1 = instanceId;
				// 1.组装数据
				List<DynamicFormInstance> newInstances = columns.stream().map(column -> {
					DynamicFormInstance instance = new DynamicFormInstance();
					buildFormInstanceData(finalInstanceId1, d, column, instance);
					return instance;
				}).collect(Collectors.toList());
				// 2.待更新数据组装，待批量入库
				formInstanceList.addAll(newInstances);
			}
			// 2.组装值班数据
			List<DutyPersonShiftDto> shiftDtos = (List<DutyPersonShiftDto>) d.get("dutyShift");
			Long finalInstanceId = instanceId;
			// 按照业务唯一索引查询主键
			List<DutyPersonShift> dutyPersonShiftsDb = dutyPersonShiftService
					.list(new LambdaQueryWrapper<DutyPersonShift>().eq(DutyPersonShift::getInstanceId, instanceId));
			Map<Date, Long> dutyPersonShiftMap = dutyPersonShiftsDb.stream()
					.collect(Collectors.toMap(DutyPersonShift::getDutyDate, DutyPersonShift::getSequenceNbr));
			// todo: 只更新当天及值班之后数据
			Set<DutyPersonShift> needToDb = shiftDtos.stream()
					.filter(s -> DateUtils.dateCompare(s.getDutyDate(), new Date()) >= 0).map(shiftDto -> {
						DutyPersonShift dutyPersonShift = new DutyPersonShift();
						Bean.copyExistPropertis(shiftDto, dutyPersonShift);
						dutyPersonShift.setInstanceId(finalInstanceId);
						dutyPersonShift.setAppKey(RequestContext.getAppKey());
						dutyPersonShift.setSequenceNbr(dutyPersonShiftMap.get(dutyPersonShift.getDutyDate()));
						return dutyPersonShift;
					}).collect(Collectors.toSet());
			dutyPersonShifts.addAll(needToDb);
		});
		if (!formInstanceList.isEmpty()) {
			dynamicFormInstanceService.saveOrUpdateBatch(formInstanceList);
		}
		if (!dutyPersonShifts.isEmpty()) {
			dutyPersonShiftService.saveOrUpdateBatch(dutyPersonShifts);
		}
	}

	public void updateFormValue(List<DynamicFormInstance> formInstanceList, Map<String, Object> d, Long instanceId,
			List<DynamicFormColumn> columns, Map<Object, DynamicFormInstance> instanceMap) {
		for (DynamicFormColumn column : columns) {
			DynamicFormInstance formInstance = instanceMap.get(column.getFieldCode());
			if (!ObjectUtils.isEmpty(formInstance)) {
				// 有的更新
				formInstance.setFieldValue(
						d.get(column.getFieldCode()) != null ? d.get(column.getFieldCode()).toString() : "");
			} else {
				// 没有的新增
				formInstance = new DynamicFormInstance();
				buildFormInstanceData(instanceId, d, column, formInstance);
			}
			formInstanceList.add(formInstance);
		}
	}

	private void buildFormInstanceData(Long instanceId, Map<String, Object> map, DynamicFormColumn column,
			DynamicFormInstance formInstance) {
		fillFormInstanceData(instanceId, map, column, formInstance, sequence.nextId());
	}

	static void fillFormInstanceData(Long instanceId, Map<String, Object> map, DynamicFormColumn column,
			DynamicFormInstance formInstance, long l) {
		Bean.copyExistPropertis(column, formInstance);
		formInstance.setAppKey(RequestContext.getAppKey());
		formInstance.setInstanceId(instanceId);
		formInstance.setSequenceNbr(l);
		formInstance.setFormColumnId(column.getSequenceNbr());
		formInstance
				.setFieldValue(map.get(column.getFieldCode()) != null ? map.get(column.getFieldCode()).toString() : "");
	}

	@Override
	public Boolean deleteDutyData(Long instanceId, String startTime, String endTime) {
        // BUG 2807 删除逻辑缺陷，现在前端后端传入 删除月份 2021-09-10 by kongfm
		//dynamicFormInstanceService.remove(new LambdaQueryWrapper<DynamicFormInstance>().eq(DynamicFormInstance::getInstanceId, instanceId));
		dutyPersonShiftService
				.remove(new LambdaQueryWrapper<DutyPersonShift>().ge(DutyPersonShift::getDutyDate,startTime).le(DutyPersonShift::getDutyDate,endTime).eq(DutyPersonShift::getInstanceId, instanceId));
		return true;
	}

	@Override
	public List<Map<String, Object>> dayDutyPersonList(String dutyDay, Long shiftId, String postType) {
		String groupCode = this.getGroupCode();
		Map<String, String> params = new HashMap<>();
		params.put("postType", postType);
		List<DynamicFormColumn> columns = dynamicFormColumnService
				.list(new LambdaQueryWrapper<DynamicFormColumn>().eq(DynamicFormColumn::getGroupCode, groupCode));
		Map<String, Object> fieldCodes = Bean.listToMap(columns, "fieldCode", "queryStrategy", DynamicFormColumn.class);
		return dynamicFormInstanceService.getBaseMapper().listOneDayDutyPerson(dutyDay, shiftId, fieldCodes,
				RequestContext.getAppKey(), groupCode, params);
	}

	@Override
	public List<Map<String, Object>> listOnDutyPerson() {
		String groupCode = this.getGroupCode();
		// 获取当前班次列表
		DateTime now = new DateTime();
		List<Long> shiftIdList = getOnDuty(now);
		String shiftIds = StringUtils.join(shiftIdList.toArray(), ",");
		String dutyDay = now.toString("yyyy-MM-dd");
		// 获取当前值班人员
		List<DynamicFormColumn> columns = dynamicFormColumnService
				.list(new LambdaQueryWrapper<DynamicFormColumn>().eq(DynamicFormColumn::getGroupCode, groupCode));
		Map<String, Object> fieldCodes = Bean.listToMap(columns, "fieldCode", "queryStrategy", DynamicFormColumn.class);
		List<Map<String, Object>> maps = dynamicFormInstanceService.getBaseMapper().listOnDutyPerson(dutyDay, shiftIds,
				fieldCodes, groupCode);
		// 获取人员照片和电话
		List<Long> ids = new ArrayList<>();
		maps.forEach(item -> ids.add(Long.valueOf(String.valueOf(item.get("userId")))));
		try {
			List<Map<String, Object>> orgUsrList = orgUsrService.selectForShowByListId(ids);
			maps.forEach(item -> {
				String userId = String.valueOf(item.get("userId"));
				for (Map<String, Object> usr : orgUsrList) {
					if (userId.equals(String.valueOf(usr.get("sequenceNbr")))) {
						item.put("personImg", usr.get("personImg"));
						item.put("telephone", usr.get("telephone"));
						break;
					}
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
		return maps;
	}

	private List<Long> getOnDuty(DateTime now) {
		List<DutyShiftDto> dutyShiftDtos = dutyShiftService.queryForDutyShiftList(false);
		List<Long> shiftIds = new ArrayList<>();
		int hour = now.getHourOfDay();
		int minute = now.getMinuteOfHour();
		dutyShiftDtos.forEach(item -> {
			String[] start = item.getStartTime().split(": ");
			String[] startTime = start[1].split(":");
			Integer startHour = Integer.valueOf(startTime[0]);
			Integer startMinute = Integer.valueOf(startTime[1]);
			String[] end = item.getEndTime().split(": ");
			String[] endTime = end[1].split(":");
			Integer endHour = Integer.valueOf(endTime[0]);
			Integer endMinute = Integer.valueOf(endTime[1]);
			if ("当日".equals(start[0])) {
				if (hour > startHour || hour == startHour && minute > startMinute) {
					if ("次日".equals(end[0])
							|| "当日".equals(end[0]) && (hour < endHour || hour == endHour && minute < endMinute)) {
						shiftIds.add(item.getSequenceNbr());
					}
				}
			}
		});
		return shiftIds;
	}

	@Override
	public List<Long> getDutyShiftIdList() {
		return getOnDuty(new DateTime());
	}
}
