/*
 * Copyright ©2023 CJB-CNIT Team. All rights reserved
 */
package com.openhis.web.inhospitalnursestation.appservice.impl;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.AgeCalculatorUtil;
import com.openhis.administration.domain.EncounterLocation;
import com.openhis.administration.service.IEncounterLocationService;
import com.openhis.administration.service.IEncounterParticipantService;
import com.openhis.administration.service.IEncounterService;
import com.openhis.administration.service.ILocationService;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.web.inhospitalnursestation.appservice.IATDManageAppService;
import com.openhis.web.inhospitalnursestation.dto.*;
import com.openhis.web.inhospitalnursestation.mapper.ATDManageAppMapper;

/**
 * 入出转管理 实现类
 *
 * @author zwh
 * @date 2025-07-28
 */
@Service
public class ATDManageAppServiceImpl implements IATDManageAppService {

    @Resource
    private ATDManageAppMapper atdManageAppMapper;

    @Resource
    private IEncounterLocationService encounterLocationService;

    @Resource
    private IEncounterParticipantService encounterParticipantService;

    @Resource
    private ILocationService locationService;

    @Resource
    private IEncounterService encounterService;

    /**
     * 入出转管理页面初始化
     *
     * @return 初始化信息
     */
    @Override
    public R<?> atdManageInit() {
        ATDManageInitDto atdManageInitDto = new ATDManageInitDto();
        // 住院状态
        List<ATDManageInitDto.encounterStatusOption> encounterStatusOptions = new ArrayList<>();
        encounterStatusOptions.add(new ATDManageInitDto.encounterStatusOption(EncounterZyStatus.REGISTERED.getValue(),
            EncounterZyStatus.REGISTERED.getInfo()));
        encounterStatusOptions
            .add(new ATDManageInitDto.encounterStatusOption(EncounterZyStatus.ADMITTED_TO_THE_HOSPITAL.getValue(),
                EncounterZyStatus.ADMITTED_TO_THE_HOSPITAL.getInfo()));
        // 床位状态
        List<ATDManageInitDto.bedStatusOption> bedStatusOptions = new ArrayList<>();
        bedStatusOptions
            .add(new ATDManageInitDto.bedStatusOption(LocationStatus.IDLE.getValue(), LocationStatus.IDLE.getInfo()));
        bedStatusOptions.add(
            new ATDManageInitDto.bedStatusOption(LocationStatus.OCCUPY.getValue(), LocationStatus.OCCUPY.getInfo()));
        // 患者病情
        List<ATDManageInitDto.priorityOption> priorityOptions = Stream.of(PriorityLevel.values())
            .map(
                priorityLevel -> new ATDManageInitDto.priorityOption(priorityLevel.getValue(), priorityLevel.getInfo()))
            .collect(Collectors.toList());
        atdManageInitDto.setBedStatusOptions(bedStatusOptions).setEncounterStatusOptions(encounterStatusOptions)
            .setPriorityOptions(priorityOptions);
        return R.ok(atdManageInitDto);
    }

    /**
     * 入院患者分页列表
     *
     * @param admissionPageParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @param searchKey 模糊查询关键字
     * @param request 请求数据
     * @return 入院患者分页列表
     */
    @Override
    public R<?> getAdmissionPatientPage(AdmissionPageParam admissionPageParam, Integer pageNo, Integer pageSize,
        String searchKey, HttpServletRequest request) {
        // 构建查询条件
        QueryWrapper<AdmissionPageParam> queryWrapper = HisQueryUtils.buildQueryWrapper(admissionPageParam, searchKey,
            new HashSet<>(Arrays.asList(CommonConstants.FieldName.PatientWbStr, CommonConstants.FieldName.PatientPyStr,
                CommonConstants.FieldName.PatientName, CommonConstants.FieldName.BusNo)),
            request);
        // 入院患者分页列表
        Page<AdmissionPatientPageDto> admissionPatientPage = atdManageAppMapper.selectAdmissionPatientPage(
            new Page<>(pageNo, pageSize), queryWrapper, EncounterClass.IMP.getValue(),
            EncounterZyStatus.TO_BE_REGISTERED.getValue(), EncounterActivityStatus.ACTIVE.getValue(),
            LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(), LocationForm.BED.getValue());
        admissionPatientPage.getRecords().forEach(e -> {
            // 性别枚举
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 病情
            e.setPriorityEnum_enumText(EnumUtils.getInfoByValue(PriorityLevel.class, e.getPriorityEnum()));
            // 计算年龄
            if (e.getBirthDate() != null) {
                e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
            }
            // 住院状态
            e.setEncounterStatus_enumText(EnumUtils.getInfoByValue(EncounterZyStatus.class, e.getEncounterStatus()));
        });
        return R.ok(admissionPatientPage);
    }

    /**
     * 入院患者床位信息分页列表
     *
     * @param admissionPageParam 查询条件
     * @param pageNo 当前页码
     * @param pageSize 查询条数
     * @return 床位信息分页列表
     */
    @Override
    public R<?> getAdmissionBedPage(AdmissionPageParam admissionPageParam, Integer pageNo, Integer pageSize) {
        // 构建查询条件
        QueryWrapper<AdmissionPageParam> queryWrapper =
            HisQueryUtils.buildQueryWrapper(admissionPageParam, null, null, null);
        // 入院患者床位分页列表
        Page<AdmissionBedPageDto> admissionBedPage =
            atdManageAppMapper.selectAdmissionBadPage(new Page<>(pageNo, pageSize), queryWrapper,
                EncounterActivityStatus.ACTIVE.getValue(), LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(),
                LocationForm.BED.getValue(), AccountType.PERSONAL_CASH_ACCOUNT.getCode(),
                LocationStatus.INACTIVE.getValue(), ChargeItemStatus.BILLABLE.getValue(),
                ChargeItemStatus.BILLED.getValue(), ChargeItemStatus.REFUNDED.getValue());
        admissionBedPage.getRecords().forEach(e -> {
            // 性别枚举
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 床位状态
            e.setBedStatus_enumText(EnumUtils.getInfoByValue(LocationStatus.class, e.getBedStatus()));
            // 计算年龄
            if (e.getBirthDate() != null) {
                e.setAge(AgeCalculatorUtil.getAge(e.getBirthDate()));
            }
            // 住院状态
            e.setEncounterStatus_enumText(EnumUtils.getInfoByValue(EncounterZyStatus.class, e.getEncounterStatus()));
        });
        return R.ok(admissionBedPage);
    }

    /**
     * 入院患者详细信息
     *
     * @param encounterId 住院id
     * @return 入院患者详细信息
     */
    @Override
    public R<?> getAdmissionPatientInfo(Long encounterId) {
        // 查询住院患者详细信息
        AdmissionPatientInfoDto admissionPatientInfoDto =
            atdManageAppMapper.selectAdmissionPatientInfo(encounterId, EncounterActivityStatus.ACTIVE.getValue(),
                LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(), LocationForm.BED.getValue(),
                ParticipantType.PRIMARY_NURSE.getCode(), ParticipantType.ATTENDING_DOCTOR.getCode(),
                ParticipantType.ADMITTING_DOCTOR.getCode(), ParticipantType.CHIEF_DOCTOR.getCode());
        // 年龄
        admissionPatientInfoDto.setAge(AgeCalculatorUtil.getAge(admissionPatientInfoDto.getBirthDate()));
        // 性别
        admissionPatientInfoDto.setGenderEnum_enumText(
            EnumUtils.getInfoByValue(AdministrativeGender.class, admissionPatientInfoDto.getGenderEnum()));
        // 病情
        admissionPatientInfoDto.setPriorityEnum_enumText(
            EnumUtils.getInfoByValue(PriorityLevel.class, admissionPatientInfoDto.getPriorityEnum()));
        return R.ok(admissionPatientInfoDto);
    }

    /**
     * 住院患者待处理信息列表
     *
     * @param encounterId 住院id
     * @return 待处理信息列表
     */
    @Override
    public R<?> getInPatientPendingList(Long encounterId) {
//        List<InpatientAdviceDto> inPatientPendingList =
//            atdManageAppMapper.selectInPatientPendingList(encounterId, EncounterActivityStatus.ACTIVE.getValue(),
//                LocationForm.WARD.getValue(), LocationForm.HOUSE.getValue(), LocationForm.BED.getValue(),
//                ParticipantType.PRIMARY_NURSE.getCode(), ParticipantType.ATTENDING_DOCTOR.getCode(),
//                ParticipantType.ADMITTING_DOCTOR.getCode());
        return null;
    }

    /**
     * 入科床位分配
     *
     * @param admissionPatientInfoDto 床位分配参数
     * @return 结果
     */
    @Override
    public R<?> admissionBedAssignment(AdmissionPatientInfoDto admissionPatientInfoDto) {
        // 住院id
        Long encounterId = admissionPatientInfoDto.getEncounterId();
        // 目标床位住院患者id
        Long targetEncounterId = admissionPatientInfoDto.getTargetEncounterId();
        // 入科时间
        Date startTime = admissionPatientInfoDto.getStartTime();
        // 患者床位id
        Long oldBedId = admissionPatientInfoDto.getBedId();
        // 目标床位id
        Long targetBedId = admissionPatientInfoDto.getTargetBedId();

        // 进入编辑患者信息，不更换床位
        if (Whether.YES.getCode().equals(admissionPatientInfoDto.getEditFlag())) {
            if (admissionPatientInfoDto.getPriorityEnum() != null) {
                // 更新患者病情
                encounterService.updatePriorityEnumById(encounterId, admissionPatientInfoDto.getPriorityEnum());
                // 将之前的住院参与者更新为已完成
                Integer result = encounterParticipantService.updateEncounterParticipantsStatus(encounterId);
                if (result == 0) {
                    return R.fail("患者信息更新失败，请联系管理员");
                }
                // 更新住院参与者
                // 住院医生
                encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                    admissionPatientInfoDto.getAdmittingDoctorId(), ParticipantType.ADMITTING_DOCTOR.getCode());
                // 责任护士
                encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                    admissionPatientInfoDto.getPrimaryNurseId(), ParticipantType.PRIMARY_NURSE.getCode());
                if (admissionPatientInfoDto.getAttendingDoctorId() != null) {
                    // 主治医生
                    encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                        admissionPatientInfoDto.getAttendingDoctorId(), ParticipantType.ATTENDING_DOCTOR.getCode());
                }
                if (admissionPatientInfoDto.getChiefDoctorId() != null) {
                    // 主任医生
                    encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                        admissionPatientInfoDto.getChiefDoctorId(), ParticipantType.CHIEF_DOCTOR.getCode());
                }
            }
            return R.ok("患者信息更新成功");
        }

        // 判断患者是否已经在床
        if (oldBedId != null) {
            // 判断目标床位是否已经被占用
            if (targetEncounterId != null) {
                List<EncounterLocation> locationList =
                    encounterLocationService.getEncounterLocationInfo(targetEncounterId, null);
                // 查询目标患者的入科时间
                Date targetStartTime = null;
                Optional<EncounterLocation> encounterLocationOptional =
                    locationList.stream().filter(x -> x.getFormEnum().equals(LocationForm.BED.getValue()))
                        .filter(x -> x.getStatusEnum().equals(EncounterActivityStatus.ACTIVE.getValue())).findFirst();
                if (encounterLocationOptional.isPresent()) {
                    EncounterLocation encounterLocation = encounterLocationOptional.get();
                    targetStartTime = encounterLocation.getStartTime();
                }
                // 床位互换
                Integer result = encounterLocationService.updateEncounterLocationStatus(encounterId, false);
                Integer targetResult = encounterLocationService.updateEncounterLocationStatus(targetEncounterId, false);
                if (result == 0 || targetResult == 0) {
                    return R.fail("换床失败，请联系管理员");
                }
                // 保存住院位置(目标床位)
                // 病房
                encounterLocationService.creatEncounterLocation(encounterId, startTime,
                    admissionPatientInfoDto.getTargetHouseId(), LocationForm.HOUSE.getValue());
                // 病床
                encounterLocationService.creatEncounterLocation(encounterId, startTime, targetBedId,
                    LocationForm.BED.getValue());

                // 保存住院位置(原床位)
                // 病房
                encounterLocationService.creatEncounterLocation(targetEncounterId, targetStartTime,
                    admissionPatientInfoDto.getHouseId(), LocationForm.HOUSE.getValue());
                // 病床
                encounterLocationService.creatEncounterLocation(targetEncounterId, targetStartTime, oldBedId,
                    LocationForm.BED.getValue());

            } else {
                // 更新旧病床状态：空闲
                locationService.updateStatusById(oldBedId, LocationStatus.IDLE.getValue());

                // 换床
                Integer result = encounterLocationService.updateEncounterLocationStatus(encounterId, false);
                if (result == 0) {
                    return R.fail("换床失败，请联系管理员");
                }
                // 保存住院位置
                // 病房
                encounterLocationService.creatEncounterLocation(encounterId, startTime,
                    admissionPatientInfoDto.getTargetHouseId(), LocationForm.HOUSE.getValue());
                // 病床
                encounterLocationService.creatEncounterLocation(encounterId, startTime, targetBedId,
                    LocationForm.BED.getValue());
                // 更新病床状态：占用
                locationService.updateStatusById(targetBedId, LocationStatus.OCCUPY.getValue());
            }
        } else {
            // 保存住院位置
            // 病房
            encounterLocationService.creatEncounterLocation(encounterId, startTime,
                admissionPatientInfoDto.getTargetHouseId(), LocationForm.HOUSE.getValue());
            // 病床
            encounterLocationService.creatEncounterLocation(encounterId, startTime, targetBedId,
                LocationForm.BED.getValue());
            // 更新病床状态：占用
            locationService.updateStatusById(targetBedId, LocationStatus.OCCUPY.getValue());

            // 保存住院参与者
            // 住院医生
            encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                admissionPatientInfoDto.getAdmittingDoctorId(), ParticipantType.ADMITTING_DOCTOR.getCode());
            // 责任护士
            encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                admissionPatientInfoDto.getPrimaryNurseId(), ParticipantType.PRIMARY_NURSE.getCode());
            if (admissionPatientInfoDto.getAttendingDoctorId() != null) {
                // 主治医生
                encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                    admissionPatientInfoDto.getAttendingDoctorId(), ParticipantType.ATTENDING_DOCTOR.getCode());
            }
            if (admissionPatientInfoDto.getChiefDoctorId() != null) {
                // 主任医生
                encounterParticipantService.creatEncounterParticipants(encounterId, startTime,
                    admissionPatientInfoDto.getChiefDoctorId(), ParticipantType.CHIEF_DOCTOR.getCode());
            }
        }
        if (admissionPatientInfoDto.getPriorityEnum() != null) {
            // 更新患者病情
            encounterService.updatePriorityEnumById(encounterId, admissionPatientInfoDto.getPriorityEnum());
        }
        // 更新住院状态：已住院
        Integer result =
            encounterService.updateEncounterStatus(encounterId, EncounterZyStatus.ADMITTED_TO_THE_HOSPITAL.getValue());
        if (result == 0) {
            return R.fail("床位分配失败，请联系管理员");
        }
        return R.ok("床位分配成功");
    }

    /**
     * 转科
     *
     * @param encounterId 住院id
     * @return 结果
     */
    @Override
    public R<?> transferDepartment(Long encounterId) {
        return null;
    }

    /**
     * 出院
     *
     * @param encounterId 住院id
     * @return 结果
     */
    @Override
    public R<?> hospitalDischarge(Long encounterId) {
        return null;
    }
}
