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.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.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 {
        String instanceId = m.get("instanceId").toString();
        List<DutyShift> dutyShifts =
                dutyShiftService.list(new LambdaQueryWrapper<DutyShift>().eq(BaseEntity::getIsDelete, false).eq(DutyShift::getAppKey, RequestContext.getAppKey()));
        Map<Long, DutyShift> keyNameMap = dutyShifts.stream().collect(Collectors.toMap(BaseEntity::getSequenceNbr,
                Function.identity()));
        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(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);
        }
        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(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) {
        dynamicFormInstanceService.remove(new LambdaQueryWrapper<DynamicFormInstance>().eq(DynamicFormInstance::getInstanceId, instanceId));
        dutyPersonShiftService.remove(new LambdaQueryWrapper<DutyPersonShift>().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;
    }

}
