package com.eitc.patient.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eitc.common.annotation.Log;
import com.eitc.common.core.controller.BaseController;
import com.eitc.common.core.domain.AjaxResult;
import com.eitc.common.core.domain.entity.SysUser;
import com.eitc.common.enums.BusinessType;
import com.eitc.patient.domain.SchedulingDetails;
import com.eitc.patient.domain.SchedulingStatus;
import com.eitc.patient.service.ISchedulingDetailsService;
import com.eitc.patient.service.ISchedulingStatusService;
import com.eitc.patient.utils.PatientUtil;
import com.eitc.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * SchedulingDetailsController
 *
 * @author mtx
 * @date: 2024/05/17 15:51
 */
@Api(tags = "排班详情")
@RestController
@RequestMapping("/scheduling-details")
public class SchedulingDetailsController extends BaseController {

    @Resource
    private ISchedulingDetailsService schedulingDetailsService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ISchedulingStatusService schedulingStatusService;

/**
 * 查询排班信息
 * 通过日期、医生名称和科室ID查询排班详情，展示医生一个月内的排班情况。
 *
 * @param date 查询的日期，格式为"yyyy-MM"
 * @param doctorName 可选参数，医生名称，用于过滤查询结果
 * @param deptId 可选参数，科室ID，用于查询指定科室下的医生排班
 * @return 返回查询结果，包含医生名称和每一天的排班状态
 * @throws ParseException 如果日期格式不正确，解析时会抛出此异常
 */
@GetMapping("/list")
@ApiOperation("查询排班详情")
public AjaxResult list(@RequestParam(name = "date") String date,
                       @RequestParam(name = "doctorName", required = false) String doctorName,
                       @RequestParam(name = "deptId", required = false) Long deptId) throws ParseException {
    // 获取所有排班状态，用于映射排班状态ID和状态名称、颜色
    List<SchedulingStatus> statusList = schedulingStatusService.list();
    Map<String, String> statusMap = statusList.stream().collect(Collectors.toMap(SchedulingStatus::getId, SchedulingStatus::getStatusName));
    Map<String, String> colorMap = statusList.stream().collect(Collectors.toMap(SchedulingStatus::getId, SchedulingStatus::getColor));
    // 根据科室ID查询医生ID列表，用于过滤排班信息
    List<Long> userIds = new ArrayList<>();
    if (Objects.nonNull(deptId)) {
        SysUser user = new SysUser();
        user.setDeptId(deptId);
        List<SysUser> users = sysUserService.selectUserList(user);
        if (CollectionUtils.isNotEmpty(users)) {
            userIds = users.stream().map(SysUser::getUserId).collect(Collectors.toList());
        }
    } else {
        userIds = null;
    }
    // 解析查询的日期，用于查询当月的排班信息
    Calendar instance = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
    Date parse = sdf.parse(date);
    instance.setTime(parse);
    // 查询当月的排班详情信息
    List<Map<String, Object>> resultList = new ArrayList<>();
    List<SchedulingDetails> list = schedulingDetailsService.list(Wrappers.<SchedulingDetails>lambdaQuery()
            .in(null != userIds, SchedulingDetails::getDoctorId, userIds)
            .eq(SchedulingDetails::getWorkYear, instance.get(Calendar.YEAR))
            .eq(SchedulingDetails::getWorkMonth, instance.get(Calendar.MONTH) + 1));
    if (CollectionUtils.isEmpty(list)) {
        return success(resultList);
    }
    // 根据医生ID分组排班详情，以便按医生展示排班信息
    Map<String, List<SchedulingDetails>> listMap = list.stream().collect(Collectors.groupingBy(SchedulingDetails::getDoctorId));
    // 查询所有医生信息，用于填充医生名称
    List<SysUser> users = sysUserService.selectUserList(new SysUser());
    for (SysUser user : users) {
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("doctorId", user.getUserId());
        map.put("doctorName", user.getNickName());
        // 构建每一天的排班信息
        List<Map<String, String>> dataList = new ArrayList<>();
        int actualMaximum = instance.getActualMaximum(Calendar.DAY_OF_MONTH);
        List<SchedulingDetails> detailsList = listMap.get(String.valueOf(user.getUserId()));
        for (int i = 1; i < actualMaximum; i++) {
            instance.set(Calendar.DAY_OF_MONTH, i);
            int d = instance.get(Calendar.DAY_OF_MONTH);
            int w = instance.get(Calendar.DAY_OF_WEEK);
            Map<String, String> detailMap = new LinkedHashMap<>();
            // 默认设置排班信息为空
            detailMap.put("id", "");
            detailMap.put("status", "");
            detailMap.put("statusCn", "");
            detailMap.put("color", "");
            detailMap.put("day", String.valueOf(d));
            detailMap.put("year", String.valueOf(instance.get(Calendar.YEAR)));
            detailMap.put("month", String.valueOf(instance.get(Calendar.MONTH) + 1));
            detailMap.put("week", PatientUtil.getWeekDay(w));
            // 如果当天有排班，则填充具体排班信息
            if (CollectionUtils.isNotEmpty(detailsList)) {
                int finalI = i;
                Optional<SchedulingDetails> details = detailsList.stream().filter(li -> li.getWorkDay() == finalI).findFirst();
                if (details.isPresent()) {
                    SchedulingDetails schedulingDetails = details.get();
                    detailMap.put("id", schedulingDetails.getId());
                    detailMap.put("status", schedulingDetails.getWorkStatus());
                    detailMap.put("statusCn", statusMap.get(schedulingDetails.getWorkStatus()));
                    detailMap.put("color", colorMap.get(schedulingDetails.getWorkStatus()));
                }
            }
            dataList.add(detailMap);
        }
        map.put("data", dataList);
        resultList.add(map);
    }
    // 根据医生名称过滤查询结果
    if (StringUtils.isNotEmpty(doctorName)) {
        resultList = resultList.stream().filter(li -> li.get("doctorName").toString().contains(doctorName)).collect(Collectors.toList());
    }
    return success(resultList);
}

    /**
     * 修改排班信息
     * 通过接收一个包含多个排班细节的列表，更新已存在的排班记录或创建新的排班记录。
     * @param mapList 包含排班信息的列表，每个元素是一个Map，其中包含医生ID和具体的排班数据。
     * @return AjaxResult 结果对象，包含操作的成功与否信息。
     */
    @Log(title = "修改排班", businessType = BusinessType.UPDATE)
    @PutMapping
    @ApiOperation("修改排班")
    public AjaxResult edit(@Valid @RequestBody List<Map<String, Object>> mapList) {
        // 检查传入的列表是否为空，为空则返回错误信息
        if (CollectionUtils.isEmpty(mapList)) {
            return error("无数据");
        }
        // 初始化一个列表用于存储待更新或创建的排班细节对象
        List<SchedulingDetails> list = new ArrayList<>();
        // 遍历传入的排班信息列表
        for (Map<String, Object> map : mapList) {
            // 检查医生ID是否为空，为空则返回错误
            if (Objects.isNull(map.get("doctorId"))) {
                return error();
            }
            // 从每个排班信息中获取具体的排班数据列表
            List<Map<String, String>> data = (List<Map<String, String>>) map.get("data");
            // 遍历每个具体的排班数据
            for (Map<String, String> datum : data) {
                // 初始化一个排班细节对象
                SchedulingDetails entry = new SchedulingDetails();
                // 从数据中填充排班细节对象的属性
                entry.setId(datum.get("id"));
                entry.setWorkStatus(datum.get("status"));
                // 如果排班ID为空，则该排班为新排班，需要设置其他属性
                if (StringUtils.isBlank(entry.getId())) {
                    entry.setDoctorId(String.valueOf(map.get("doctorId")));
                    entry.setWorkYear(Integer.valueOf(datum.get("year")));
                    entry.setWorkMonth(Integer.valueOf(datum.get("month")));
                    entry.setWorkDay(Integer.valueOf(datum.get("day")));
                    // 根据排班的年月日计算排班日期，并设置到对象中
                    Calendar instance = Calendar.getInstance();
                    instance.set(Calendar.YEAR, entry.getWorkYear());
                    instance.set(Calendar.MONTH, entry.getWorkMonth() - 1);
                    instance.set(Calendar.DAY_OF_MONTH, entry.getWorkDay());
                    entry.setWorkDate(instance.getTime());
                }
                // 将排班细节对象添加到待处理列表中
                list.add(entry);
            }
        }
        // 调用服务层方法批量保存或更新排班细节对象，并返回操作结果
        return toAjax(schedulingDetailsService.saveOrUpdateBatch(list));
    }

}
