package com.eitc.patient.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eitc.common.core.domain.entity.SysDept;
import com.eitc.common.core.domain.entity.SysUser;
import com.eitc.common.utils.PatientBaseUtil;
import com.eitc.patient.domain.Patient;
import com.eitc.patient.domain.PatientAppointment;
import com.eitc.patient.dto.PatientAppointmentDto;
import com.eitc.patient.enums.PatientAppointmentStatusEnum;
import com.eitc.patient.enums.PatientAppointmentVisitTypeEnum;
import com.eitc.patient.enums.PatientCreateTypeEnum;
import com.eitc.patient.mapper.PatientAppointmentMapper;
import com.eitc.patient.service.IPatientAppointmentService;
import com.eitc.patient.service.IPatientService;
import com.eitc.patient.utils.PatientUtil;
import com.eitc.patient.vo.PatientAppointmentParamVO;
import com.eitc.patient.vo.PatientAppointmentVO;
import com.eitc.system.utils.UserCacheUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.eitc.common.utils.PageUtils.startPage;

/**
 * PatientAppointmentServiceImpl
 *
 * @author mtx
 * @date: 2024/05/17 15:38
 */
@Service
public class PatientAppointmentServiceImpl extends ServiceImpl<PatientAppointmentMapper, PatientAppointment> implements IPatientAppointmentService {

    @Resource
    private IPatientService patientService;

    /**
     * 添加预约记录
     *
     * @param entry 参数
     * @author mtx
     * @date: 2024/5/21 8:56
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void addOrEdit(PatientAppointmentVO entry) {
        // 同一个医生同一时段不能预约
        checkAppointmentTime(entry.getAttendingDoctor(), entry.getAppointmentStartTime(), entry.getAppointmentEndTime());

        // 保存患者信息，根据身份证号搜索，搜索到了则更新，搜索不到则修改
        Patient patient = new Patient();
        String identificationCard = entry.getIdentificationCard();
        Patient one = patientService.getOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getIdentificationCard, identificationCard));
        if (Objects.nonNull(one)) {
            patient.setId(one.getId());
        } else {
            patient.setMedicalRecordNum(patientService.findMedicalRecordNum());
        }
        patient.setPatientName(entry.getPatientName());
        patient.setBirthday(entry.getBirthday());
        patient.setSex(entry.getSex());
        patient.setIdentificationCard(entry.getIdentificationCard());
        patient.setPatientSource(entry.getPatientSource());
        patient.setRemark(entry.getRemark());
        patient.setCreateType(PatientCreateTypeEnum.PC.getCode());
        patient.setPersonalRelationship(entry.getPersonalRelationship());
        patient.setPatientPhone(entry.getLinkPhone());
        patient.setLinkPhone(entry.getLinkPhone());
        patientService.saveOrUpdate(patient);

        // 保存预约信息
        long count = this.count(Wrappers.<PatientAppointment>lambdaQuery().eq(PatientAppointment::getAppointmentPersonId, patient.getId()));
        PatientAppointment patientAppointment = new PatientAppointment();
        patientAppointment.setOutpatientService(entry.getOutpatientService());
        patientAppointment.setDepartment(entry.getDepartment());
        patientAppointment.setAppointmentType(entry.getAppointmentType());
        patientAppointment.setAttendingDoctorId(UserCacheUtil.getSysUserByUserName(entry.getAttendingDoctor()).getUserId().toString());
        patientAppointment.setAttendingDoctor(entry.getAttendingDoctor());
        patientAppointment.setVisitType(count > 0 ?
                PatientAppointmentVisitTypeEnum.REVIEW.getCode() : PatientAppointmentVisitTypeEnum.INITIAL_DIAGNOSIS.getCode());
        patientAppointment.setAppointmentPersonId(patient.getId());
        patientAppointment.setAppointmentPerson(patient.getPatientName());
        patientAppointment.setAppointmentStartTime(entry.getAppointmentStartTime());
        patientAppointment.setAppointmentEndTime(entry.getAppointmentEndTime());
        patientAppointment.setAppointmentProject(entry.getAppointmentProject());
        patientAppointment.setAppointmentStatus(Objects.nonNull(entry.getAppointmentStatus()) ? entry.getAppointmentStatus() : PatientAppointmentStatusEnum.RESERVATION.getCode());
        patientAppointment.setRegisterUserId(entry.getRegisterUserId());
        patientAppointment.setRegisterUser(UserCacheUtil.getSysUserById(entry.getRegisterUserId()).getNickName());
        patientAppointment.setRemark(entry.getRemark());
        if (Objects.nonNull(entry.getAppointmentId())) {
            patientAppointment.setId(entry.getAppointmentId());
        }
        this.saveOrUpdate(patientAppointment);
    }

    /**
     * 同一个医生同一时段不能预约
     *
     * @param attendingDoctor 医生
     * @param startTime       开始时间
     * @param endTime         结束时间
     * @author mtx
     * @date: 2024/6/14 17:13
     */
    @Override
    public void checkAppointmentTime(String attendingDoctor, Date startTime, Date endTime) {
        List<PatientAppointment> list = this.list(Wrappers.<PatientAppointment>lambdaQuery()
                .eq(PatientAppointment::getAttendingDoctorId, attendingDoctor));
        for (PatientAppointment patientAppointment : list) {
            // 判断时间是否重叠
            if (PatientBaseUtil.isOverlapLocalTime(startTime, endTime, patientAppointment.getAppointmentStartTime(), patientAppointment.getAppointmentEndTime())) {
                throw new RuntimeException("当前医生当天时间已有预约，请选择预约其他时间段");
            }
        }
    }

    /**
     * 根据条件查询患者预约信息列表。
     *
     * @param patientAppointmentParamVO 查询条件参数对象。
     * @return 患者预约信息列表。
     * @author mtx
     * @date 2024/5/27 9:26
     */
    @Override
    public List<PatientAppointmentDto> findList(PatientAppointmentParamVO patientAppointmentParamVO) {
        List<Long> userIdList = null;
        try {
            List<SysUser> sysUserList = PatientUtil.findUserListByLoginUser();
            userIdList = sysUserList.stream().map(SysUser::getUserId).collect(Collectors.toList());
        } catch (Exception ignored) {
        }

        startPage();
        // 如果预约结束时间存在，则将其设置为第二天的开始时间，以便查询包含当天结束时间的预约
        if (Objects.nonNull(patientAppointmentParamVO.getAppointmentEndTime())) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(patientAppointmentParamVO.getAppointmentEndTime());
            instance.add(Calendar.DATE, 1);
            patientAppointmentParamVO.setAppointmentEndTime(instance.getTime());
        }

        // 构建查询条件，使用Lambda表达式方式
        LambdaQueryWrapper<PatientAppointment> eq = Wrappers.<PatientAppointment>lambdaQuery()
                // 查询预约状态在指定数组中的记录
                .in(Objects.nonNull(patientAppointmentParamVO.getAppointmentStatusArray()), PatientAppointment::getAppointmentStatus, patientAppointmentParamVO.getAppointmentStatusArray())
                // 查询预约开始时间大于等于指定时间的记录
                .ge(Objects.nonNull(patientAppointmentParamVO.getAppointmentStartTime()), PatientAppointment::getAppointmentStartTime, patientAppointmentParamVO.getAppointmentStartTime())
                // 查询预约结束时间小于等于指定时间的记录
                .le(Objects.nonNull(patientAppointmentParamVO.getAppointmentEndTime()), PatientAppointment::getAppointmentEndTime, patientAppointmentParamVO.getAppointmentEndTime())
                // 查询指定医生的预约记录
                .in(CollectionUtils.isNotEmpty(userIdList), PatientAppointment::getAttendingDoctorId, userIdList)
                .eq(Objects.nonNull(patientAppointmentParamVO.getAttendingDoctor()), PatientAppointment::getAttendingDoctor, patientAppointmentParamVO.getAttendingDoctor())
                // 查询指定患者的预约记录
                .eq(Objects.nonNull(patientAppointmentParamVO.getAppointmentPersonId()), PatientAppointment::getAppointmentPersonId, patientAppointmentParamVO.getAppointmentPersonId())
                // 按更新时间降序排序
                .orderByDesc(PatientAppointment::getCreateDate);

        // 根据条件查询预约信息列表
        List<PatientAppointment> list = this.list(eq);

        // 如果查询结果为空，则返回空列表
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }

        // 将查询到的预约信息转换为 DTO 对象列表后返回
        return list.stream().map(this::getPatientAppointmentDto).collect(Collectors.toList());
    }


    /**
     * 封装预约信息，将数据库中的预约实体转换为用于前端展示的DTO（数据传输对象）。
     *
     * @param appointment 预约信息实体，来源于数据库。
     * @return 返回封装好地预约信息DTO，供前端使用。
     * @author mtx
     * @date: 2024/5/24 11:13
     */
    @Override
    public PatientAppointmentDto getPatientAppointmentDto(PatientAppointment appointment) {
        PatientAppointmentDto dto = new PatientAppointmentDto();
        // 如果预约实体为空，则直接返回空的DTO对象
        if (Objects.isNull(appointment)) {
            return dto;
        }
        // 通过预约人员ID获取患者信息
        Patient patient = patientService.getById(appointment.getAppointmentPersonId());

        // 将患者预约信息从实体转换为DTO
        dto.setAppointmentId(appointment.getId());
        dto.setMedicalRecordNum(patient.getMedicalRecordNum()); // 设置患者用户编号
        dto.setPatientName(patient.getPatientName()); // 设置患者姓名
        dto.setDepartment(appointment.getDepartment()); // 设置预约科室ID
        // 获取科室名称并设置
        dto.setSex(patient.getSex()); // 设置患者性别
        dto.setPatientSource(patient.getPatientSource()); // 设置患者来源
        dto.setAttendingDoctor(appointment.getAttendingDoctor()); // 设置主治医生ID
        dto.setRegisterUserId(appointment.getRegisterUserId()); // 设置挂号人员ID
        // 获取挂号人员姓名并设置
        dto.setRegisterUserName(appointment.getRegisterUser());
        dto.setAppointmentStartTime(appointment.getAppointmentStartTime()); // 设置预约开始时间
        dto.setAppointmentEndTime(appointment.getAppointmentEndTime()); // 设置预约结束时间
        dto.setAppointmentProject(appointment.getAppointmentProject()); // 设置预约项目
        dto.setRemark(StringUtils.isNotEmpty(patient.getRemark()) ? patient.getRemark() : "无"); // 设置备注信息
        dto.setVisitType(appointment.getVisitType()); // 设置就诊类型
        dto.setCreateDate(appointment.getCreateDate()); // 设置创建日期
        dto.setAppointmentStatus(appointment.getAppointmentStatus()); // 设置预约状态
        // 获取医生姓名并设置
        SysUser sysUserById = UserCacheUtil.getSysUserById(appointment.getAttendingDoctorId());
        if (Objects.nonNull(sysUserById)) {
            SysDept sysDept = UserCacheUtil.getSysDeptById(sysUserById.getDeptId());
            dto.setAttendingDoctorDepCn(Objects.nonNull(sysDept) ? sysDept.getDeptName() : null);
        }
        dto.setOutpatientService(appointment.getOutpatientService());
        dto.setIdentificationCard(patient.getIdentificationCard());
        dto.setAppointmentType(appointment.getAppointmentType());
        dto.setBirthday(patient.getBirthday());
        if (StringUtils.isBlank(patient.getPersonalRelationship())) {
            dto.setLinkPhone(patient.getPatientPhone());
            dto.setPersonalRelationship("本人");
        } else {
            dto.setLinkPhone(patient.getLinkPhone());
            dto.setPersonalRelationship(patient.getPersonalRelationship());
        }
        dto.setPatientId(patient.getId());

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        dto.setGroupTime(sdf.format(appointment.getAppointmentStartTime()));
        return dto;
    }


}
