package com.example.hospital.api.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.BiMap;
import cn.hutool.core.map.MapUtil;
import com.example.hospital.api.controller.form.vo.DoctorScheduleSlotVO;
import com.example.hospital.api.db.dao.DoctorWorkPlanDao;
import com.example.hospital.api.db.dao.DoctorWorkPlanScheduleDao;
import com.example.hospital.api.db.pojo.DoctorWorkPlanScheduleEntity;
import com.example.hospital.api.exception.HospitalException;
import com.example.hospital.api.service.DoctorWorkPlanScheduleService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Service
public class DoctorWorkPlanScheduleServiceImpl implements DoctorWorkPlanScheduleService {
    @Resource
    private DoctorWorkPlanScheduleDao doctorWorkPlanScheduleDao;

    @Resource
    private DoctorWorkPlanDao doctorWorkPlanDao;

    @Resource
    private RedisTemplate redisTemplate;

    //hutool库提供的可以双向查找的Map
    private BiMap<String, Integer> range = new BiMap<>(new HashMap() {{
        put("08:00", 1);
        put("08:30", 2);
        put("09:00", 3);
        put("09:30", 4);
        put("10:00", 5);
        put("10:30", 6);
        put("11:00", 7);
        put("11:30", 8);
        put("13:00", 9);
        put("13:30", 10);
        put("14:00", 11);
        put("14:30", 12);
        put("15:00", 13);
        put("15:30", 14);
        put("16:00", 15);
    }});

    @Override
    public void insert(ArrayList<DoctorWorkPlanScheduleEntity> list) {
        this.insertScheduleHandle(list);
        //设置Redis缓存，用于防止挂号超售
        this.addScheduleCache(list);
    }

    @Override
    public ArrayList searchDeptSubSchedule(Map param) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchDeptSubSchedule(param);
        ArrayList<HashMap> result = new ArrayList<>();

        int tempDoctorId = 0;
        HashMap doctor = new HashMap();
        for (HashMap map : list) {
            int doctorId = MapUtil.getInt(map, "doctorId");
            int slot = MapUtil.getInt(map, "slot");
            if (tempDoctorId != doctorId) {
                tempDoctorId = doctorId;
                doctor = map;
                doctor.replace("slot", new ArrayList<>() {{
                    add(slot);
                }});
                result.add(doctor);
            } else if (tempDoctorId == doctorId) {
                ArrayList<Integer> slotList = (ArrayList) doctor.get("slot");
                slotList.add(slot);
            }
        }
        for (HashMap map : result) {
            ArrayList<Integer> slot = (ArrayList) map.get("slot");
            ArrayList tempSlot = new ArrayList();
            for (int i = 1; i <= 15; i++) {
                tempSlot.add(slot.contains(i));
            }
            map.replace("slot", tempSlot);
        }
        return result;
    }

    @Override
    public HashMap searchByWorkPlanId(int workPlanId) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchByWorkPlanId(workPlanId);
        HashMap result=new HashMap();
        ArrayList temp=new ArrayList();
        for (int i = 0; i < list.size(); i++) {
            HashMap map = list.get(i);
            int scheduleId = MapUtil.getInt(map, "scheduleId");
            int doctorId = MapUtil.getInt(map, "doctorId");
            int maximum = MapUtil.getInt(map, "maximum");
            int num = MapUtil.getInt(map, "num");
            int slot = MapUtil.getInt(map, "slot");
            if(i==0){
                result.put("doctorId",doctorId);
                result.put("maximum",maximum);
            }
            temp.add(new HashMap<>(){{
                put("scheduleId", scheduleId);
                put("slot", slot);
                put("num", num);
            }});
        }
        result.put("slots",temp);
        return result;
    }

    @Override
    public void updateSchedule(Map param) {
        ArrayList<DoctorWorkPlanScheduleEntity> addList = this.insertOrDeleteScheduleHandle(param);
        this.addScheduleCache(addList);
    }

    @Override
    @Transactional
    public void deleteByWorkPlanId(int workPlanId) {
        ArrayList<HashMap> list = doctorWorkPlanScheduleDao.searchByWorkPlanId(workPlanId);
        doctorWorkPlanScheduleDao.deleteByWorkPlanId(workPlanId);
        list.forEach(one->{
            int scheduleId = MapUtil.getInt(one, "scheduleId");
            String key = "doctor_schedule_" + scheduleId;
            redisTemplate.delete(key);
        });
    }


    @Transactional
    ArrayList<DoctorWorkPlanScheduleEntity> insertOrDeleteScheduleHandle(Map param){
        doctorWorkPlanDao.updateMaximum(param);

        Integer workPlanId = MapUtil.getInt(param, "workPlanId");
        Integer maximum = MapUtil.getInt(param, "maximum");
        ArrayList<DoctorScheduleSlotVO> slots=(ArrayList<DoctorScheduleSlotVO>) param.get("slots");
        ArrayList<DoctorWorkPlanScheduleEntity> addList = new ArrayList();
        ArrayList<Integer> removeList = new ArrayList();
        slots.forEach(one->{
            if(one.getOperate().equals("insert")){
                DoctorWorkPlanScheduleEntity entity = new DoctorWorkPlanScheduleEntity();
                entity.setWorkPlanId(workPlanId);
                entity.setMaximum(maximum);
                entity.setSlot(one.getSlot());
                addList.add(entity);
            }
            else{
                removeList.add(one.getScheduleId());
            }
        });
        if(removeList.size()>0){
            long sum = doctorWorkPlanScheduleDao.searchSumNumByIds(removeList);
            if(sum>0){
                throw new HospitalException("修改失败，本次修改与已经挂号记录冲突");
            }
            doctorWorkPlanScheduleDao.deleteByIds(removeList);
            removeList.forEach(one->{
                String key = "doctor_schedule_" + one;
                redisTemplate.delete(key);
            });
        }
        addList.forEach(one->{
            doctorWorkPlanScheduleDao.insert(one);
        });
        return addList;
    }

    @Transactional
    void insertScheduleHandle(ArrayList<DoctorWorkPlanScheduleEntity> list) {
        for (DoctorWorkPlanScheduleEntity entity : list) {
            doctorWorkPlanScheduleDao.insert(entity);
        }
    }

    private void addScheduleCache(ArrayList<DoctorWorkPlanScheduleEntity> list) {
        if (list == null || list.size() == 0) {
            return;
        }
        int workPlanId = list.get(0).getWorkPlanId();
        ArrayList<HashMap> newList = doctorWorkPlanScheduleDao.searchNewSchedule(workPlanId);
        for (HashMap one : newList) {
            int id = MapUtil.getInt(one, "id");
            int slot = MapUtil.getInt(one, "slot");
            String key = "doctor_schedule_" + id;
            redisTemplate.opsForHash().putAll(key, one);
            String date = MapUtil.getStr(one, "date");
            String time = range.getKey(slot);
            redisTemplate.expireAt(key, DateUtil.parse(date + " " + time));

        }
    }
}
