package com.openhis.web.inpatientmanage.appservice.impl;

import java.util.*;

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.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.AgeCalculatorUtil;
import com.core.common.utils.DateUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.administration.domain.Encounter;
import com.openhis.administration.domain.EncounterLocation;
import com.openhis.administration.domain.Organization;
import com.openhis.administration.service.IEncounterLocationService;
import com.openhis.administration.service.IEncounterService;
import com.openhis.administration.service.ILocationService;
import com.openhis.administration.service.IOrganizationService;
import com.openhis.common.enums.*;
import com.openhis.common.enums.ybenums.PriorityType;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.web.chargemanage.dto.OrgMetadata;
import com.openhis.web.inpatientmanage.appservice.IPatientHomeAppService;
import com.openhis.web.inpatientmanage.dto.PatientHomeDto;
import com.openhis.web.inpatientmanage.dto.PatientHomeEmptyBedDto;
import com.openhis.web.inpatientmanage.dto.PatientHomeSearchParam;
import com.openhis.web.inpatientmanage.mapper.PatientHomeAppMapper;

/**
 * 患者首页 实现类
 *
 * @author SY
 * @since 2025/05/19
 */
@Service
public class PatientHomeAppServiceImpl implements IPatientHomeAppService {

    @Resource
    private PatientHomeAppMapper patientHomeAppMapper;

    @Resource
    private ILocationService locationService;

    @Resource
    private IEncounterLocationService encounterLocationService;

    @Resource
    private IOrganizationService iOrganizationService;

    @Resource
    private IEncounterService encounterService;

    /**
     * 患者首页信息初期数据列表
     *
     * @return 患者首页初期数据列表
     */
    @Override
    public R<?> getPatientInfoInit(PatientHomeSearchParam patientHomeSearchParam, String searchKey, Integer pageNo,
        Integer pageSize, HttpServletRequest request) {

        // 构建查询条件
        QueryWrapper<PatientHomeDto> queryWrapper = HisQueryUtils.buildQueryWrapper(patientHomeSearchParam, searchKey,
            new HashSet<>(Arrays.asList("inpatientNumber", "name", "responsibleDoctor", "responsibleNurse")), request);

        // 分页查询,查询患者信息
        IPage<PatientHomeDto> patientHomeInfoPage = patientHomeAppMapper.getPage(new Page<>(pageNo, pageSize),
            patientHomeSearchParam.getStatusEnum(), patientHomeSearchParam.getPatientId(), searchKey, queryWrapper);

        patientHomeInfoPage.getRecords().forEach(e -> {
            // 护理级别
            e.setPriorityEnum_enumText(EnumUtils.getInfoByValue(PriorityType.class, e.getPriorityEnum()));
            // 费别
            e.setTypeCode_dictText(EnumUtils.getInfoByValue(AccountType.class, e.getTypeCode()));
            // 血型ABO
            e.setBloodAbo_enumText(EnumUtils.getInfoByValue(BloodTypeABO.class, e.getBloodAbo()));
            // 血型RH
            e.setBloodRh_enumText(EnumUtils.getInfoByValue(BloodTypeRH.class, e.getBloodRh()));
            // 患者状态
            e.setStatusEnum_enumText(EnumUtils.getInfoByValue(EncounterStatus.class, e.getStatusEnum()));
            // 职业
            e.setPrfsEnum_enumText(EnumUtils.getInfoByValue(OccupationType.class, e.getPrfsEnum()));
            // 联系人关系
            e.setLinkRelationCode_codeText(
                EnumUtils.getInfoByValue(FamilyRelationshipType.class, e.getLinkRelationCode()));
            // 婚姻状态
            e.setMaritalStatusEnum_enumText(EnumUtils.getInfoByValue(MaritalStatus.class, e.getMaritalStatusEnum()));
            // 就诊类别
            e.setClassEnum_enumText(EnumUtils.getInfoByValue(EncounterClass.class, e.getClassEnum()));
            // 性别枚举类回显赋值
            e.setGenderEnum_enumText(EnumUtils.getInfoByValue(AdministrativeGender.class, e.getGenderEnum()));
            // 计算年龄
            e.setAgeString(AgeCalculatorUtil.getAge(e.getBirthDate()));
            // 计算住院天数
            if (e.getClassEnum() == EncounterClass.IMP.getValue()) {
                // 截至时间,用于计算当前时刻下显示的住院天数
                if (e.getAdmissionDate() != null) {
                    Date endTime;
                    if (e.getDischargeDate() == null) {
                        endTime = DateUtils.getNowDate();
                    } else {
                        endTime = e.getDischargeDate();
                    }

                    int days = DateUtils.differentDaysByMillisecond(e.getAdmissionDate(), endTime);
                    e.setHospitalizationDays(days);
                }
            }
            // 手术状态
            e.setSurgeryStatusEnum_enumText(EnumUtils.getInfoByValue(EventStatus.class, e.getSurgeryStatusEnum()));
            // 计算术后天数
            if (e.getSurgeryStatusEnum() == EventStatus.COMPLETED.getValue()) {
                // 截至时间,用于计算当前时刻下显示的术后天数
                if (e.getSurgeryStartTime() != null && e.getSurgeryEndTime() != null) {
                    Date endTime = e.getSurgeryEndTime();
                    int days = DateUtils.differentDaysByMillisecond(endTime, DateUtils.getNowDate());
                    e.setPostoperativeDays(days);
                }
            }

        });

        // 返回【患者信息列表DTO】分页
        return R.ok(patientHomeInfoPage);

    }

    /**
     * 空床详细查询
     *
     * @param organizationId 科室ID
     * @return 空床详细查询
     */
    @Override
    public R<?> getEmptyBed(Long organizationId) {
        // 查询科室空床
        List<PatientHomeEmptyBedDto> emptyBedList = patientHomeAppMapper.getEmptyBedList(organizationId);

        return R.ok(emptyBedList);

    }

    /**
     * 转床确认
     *
     * @param encounterLocationId 就诊位置ID
     * @param encounterId 就诊ID
     * @param oldLocationId 旧位置ID
     * @param newLocationId 新位置ID
     * @return 转床结果
     */
    @Override
    public R<?> saveBedTransfer(Long encounterLocationId, Long encounterId, Long oldLocationId, Long newLocationId) {

        // 1.就诊位置ID变更
        EncounterLocation encounterLocation = new EncounterLocation();
        encounterLocation.setId(encounterLocationId)
            // 设置就诊ID
            .setEncounterId(encounterId)
            // 设置位置ID
            .setLocationId(newLocationId)
            // 设置物理枚举为 8:病床
            .setFormEnum(LocationForm.BED.getValue())
            // 状态为使用中
            .setStatusEnum(EncounterActivityStatus.ACTIVE.getValue());
        encounterLocationService.saveOrUpdateEncounterLocation(encounterLocation);

        // 2.位置表
        // 旧病床状态变更（空闲）
        locationService.updateStatusById(oldLocationId, LocationBedStatus.U.getValue());

        // 新病床状态变更（占用）
        locationService.updateStatusById(newLocationId, LocationBedStatus.O.getValue());
        // 转床结果
        return R.ok(null);
    }

    /**
     * 科室信息
     *
     * @return 科室列表
     */
    @Override
    public List<OrgMetadata> getCaty() {
        List<Organization> list = iOrganizationService.getList(OrganizationType.DEPARTMENT.getValue(),
            OrganizationClass.INPATIENT.getValue());
        List<OrgMetadata> orgMetadataList = new ArrayList<>();
        OrgMetadata orgMetadata;
        for (Organization organization : list) {
            orgMetadata = new OrgMetadata();
            BeanUtils.copyProperties(organization, orgMetadata);
            orgMetadataList.add(orgMetadata);
        }
        return orgMetadataList;
    }

    /**
     * 转科确认
     *
     * @param encounterId 就诊ID
     * @param organizationId 机构ID
     * @return 转科结果
     */
    @Override
    public R<?> saveDepartmentTransfer(Long encounterLocationId, Long patientId, Long encounterId, Long organizationId,
        Date DepartmentTransferYmd) {

        boolean encounterSuccess;
        // 1.就诊管理表变更
        // 科室变更
        Encounter encounter = new Encounter();
        // 就诊ID
        encounter.setId(encounterId)
            // 患者ID
            .setPatientId(patientId)
            // 机构ID
            .setOrganizationId(organizationId);

        encounterService.saveOrUpdateEncounter(encounter);

        // 2.就诊位置表变更
        // 就诊位置ID变更
        EncounterLocation encounterLocation = new EncounterLocation();
        encounterLocation.setId(encounterLocationId)
            // 设置就诊ID
            .setEncounterId(encounterId)
            // 设置开始时间
            .setStartTime(DepartmentTransferYmd)
            // 设置物理枚举为 8:病床
            .setFormEnum(LocationForm.BED.getValue());
        encounterSuccess = encounterLocationService.saveOrUpdateEncounterLocation(encounterLocation);

        // 转床结果
        return R.ok(encounterSuccess);
    }

    /**
     * 出院确认
     *
     * @param patientId 患者ID
     * @param encounterId 就诊ID
     * @return 转科结果
     */
    @Override
    public R<?> saveDischargeHospital(Long encounterLocationId, Long patientId, Long encounterId, Long locationId,
        Date DischargeHospitalYmd) {

        // 出院
        boolean encounterSuccess;
        // 1.就诊管理表
        Encounter encounter = new Encounter();
        // 就诊ID
        encounter.setId(encounterId)
            // 患者ID
            .setPatientId(patientId)
            // 状态编码
            .setStatusEnum(EncounterStatus.COMPLETED.getValue())
            // 结束时间
            .setEndTime(DischargeHospitalYmd);

        encounterService.saveOrUpdateEncounter(encounter);

        // 2.就诊位置表变更
        // 就诊位置ID变更
        EncounterLocation encounterLocation = new EncounterLocation();
        encounterLocation.setId(encounterLocationId)
            // 设置就诊ID
            .setEncounterId(encounterId)
            // 设置状态枚举
            .setStatusEnum(EncounterActivityStatus.COMPLETED.getValue())
            // 设置物理枚举为 8:病床
            .setFormEnum(LocationForm.BED.getValue());
        encounterLocationService.saveOrUpdateEncounterLocation(encounterLocation);

        // 3.位置表
        // 旧病床状态变更（空闲）
        encounterSuccess = locationService.updateStatusById(locationId, LocationBedStatus.U.getValue());

        // 转床结果
        return R.ok(encounterSuccess);
    }
}
