package com.eitc.patient.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eitc.common.core.controller.BaseController;
import com.eitc.common.core.domain.AjaxResult;
import com.eitc.patient.domain.CollectCostPatients;
import com.eitc.patient.domain.MedicalRecord;
import com.eitc.patient.domain.Patient;
import com.eitc.patient.domain.PatientAppointment;
import com.eitc.patient.domain.PatientFollowUp;
import com.eitc.patient.service.ICollectCostPatientsService;
import com.eitc.patient.service.IMedicalRecordDetailsService;
import com.eitc.patient.service.IMedicalRecordService;
import com.eitc.patient.service.IPatientAppointmentService;
import com.eitc.patient.service.IPatientFollowUpService;
import com.eitc.patient.service.IPatientService;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * OperationsAnalysisController
 *
 * @author mtx
 * @date: 2024/07/23 11:35
 */
@Api(tags = "运营分析")
@RestController
@RequestMapping("/operations-analysis")
public class OperationsAnalysisController extends BaseController {

    @Resource
    private IPatientService patientService;
    @Resource
    private IPatientAppointmentService patientAppointmentService;
    @Resource
    private IMedicalRecordService medicalRecordService;
    @Resource
    private IPatientFollowUpService patientFollowUpService;
    @Resource
    private ICollectCostPatientsService collectCostPatientsService;
    @Resource
    private IMedicalRecordDetailsService medicalRecordDetailsService;


    @GetMapping("/list")
    @ApiOperation("查询收费分类详情列表")
    public AjaxResult list(@RequestParam Map<String, String> map) throws ParseException {
        Map<String, Object> result = new HashMap<>();

        // 根据搜索条件封装参数 筛选项：时间段（开始时间-结束时间，按天，默认当年第一天到现在）
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date startDate = getStartDate(sdf, map.get("startDate"));
        Date endDate = getEndDate(sdf, map.get("endDate"));

        // 患者个数
        long patientCount = patientService.count(Wrappers.<Patient>lambdaQuery()
                .gt(Objects.nonNull(startDate), Patient::getCreateDate, startDate)
                .lt(Objects.nonNull(endDate), Patient::getCreateDate, endDate));
        result.put("patientCount", patientCount);

        // 预约个数
        List<PatientAppointment> patientAppointmentList = patientAppointmentService.list(Wrappers.<PatientAppointment>lambdaQuery()
                .in(PatientAppointment::getAppointmentStatus, 1, 4, 5, 6, 8)
                .gt(Objects.nonNull(startDate), PatientAppointment::getAppointmentStartTime, startDate)
                .lt(Objects.nonNull(endDate), PatientAppointment::getAppointmentStartTime, endDate));
        result.put("patientAppointmentCount", patientAppointmentList.size());

        // 就诊数
        long medicalRecordCount = medicalRecordService.count(Wrappers.<MedicalRecord>lambdaQuery()
                .gt(Objects.nonNull(startDate), MedicalRecord::getCreateDate, startDate)
                .lt(Objects.nonNull(endDate), MedicalRecord::getCreateDate, endDate));
        result.put("medicalRecordCount", medicalRecordCount);

        // 回访数
        long patientFollowUpCount = patientFollowUpService.count(Wrappers.<PatientFollowUp>lambdaQuery()
                .gt(Objects.nonNull(startDate), PatientFollowUp::getFollowUpTime, startDate)
                .lt(Objects.nonNull(endDate), PatientFollowUp::getFollowUpTime, endDate));
        result.put("patientFollowUpCount", patientFollowUpCount);

        List<CollectCostPatients> collectCostPatientsList = collectCostPatientsService.list();
        // 应收费用
        BigDecimal receivableCost = collectCostPatientsList.stream().map(CollectCostPatients::getReceivableCost)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        result.put("receivableCost", receivableCost);

        // 实收费用
        BigDecimal netReceiptsCost = collectCostPatientsList.stream().map(CollectCostPatients::getNetReceiptsCost)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        result.put("netReceiptsCost", netReceiptsCost);

        // 预约状态统计（预约，待复诊，治疗完成，已结账，已失约）
        List<Map<String, String>> patientAppointmentStatusList = new ArrayList<>();
        Map<String, String> patientAppointmentStatus = new HashMap<>();
        patientAppointmentStatus.put("name", "预约");
        patientAppointmentStatus.put("count", String.valueOf(patientAppointmentList.stream().filter(item -> Objects.equals(item.getAppointmentStatus(), 1)).count()));
        patientAppointmentStatusList.add(patientAppointmentStatus);
        patientAppointmentStatus = new HashMap<>();
        patientAppointmentStatus.put("name", "待复诊");
        patientAppointmentStatus.put("count", String.valueOf(patientAppointmentList.stream().filter(item -> Objects.equals(item.getAppointmentStatus(), 4)).count()));
        patientAppointmentStatusList.add(patientAppointmentStatus);
        patientAppointmentStatus = new HashMap<>();
        patientAppointmentStatus.put("name", "治疗完成");
        patientAppointmentStatus.put("count", String.valueOf(patientAppointmentList.stream().filter(item -> Objects.equals(item.getAppointmentStatus(), 5)).count()));
        patientAppointmentStatusList.add(patientAppointmentStatus);
        patientAppointmentStatus = new HashMap<>();
        patientAppointmentStatus.put("name", "已结账");
        patientAppointmentStatus.put("count", String.valueOf(patientAppointmentList.stream().filter(item -> Objects.equals(item.getAppointmentStatus(), 6)).count()));
        patientAppointmentStatusList.add(patientAppointmentStatus);
        patientAppointmentStatus = new HashMap<>();
        patientAppointmentStatus.put("name", "已失约");
        patientAppointmentStatus.put("count", String.valueOf(patientAppointmentList.stream().filter(item -> Objects.equals(item.getAppointmentStatus(), 8)).count()));
        patientAppointmentStatusList.add(patientAppointmentStatus);
        result.put("patientAppointmentStatus", patientAppointmentStatusList);

        // 诊断统计（列出诊断类型前十名及个数）
        List<Map<String, String>> diagnosisCountList = medicalRecordDetailsService.countByDiagnosisTypeName();
        result.put("diagnosisCount", diagnosisCountList);

        return success(result);
    }

    /**
     * 根据传入的日期字符串和日期格式，获取结束日期。
     * 如果日期字符串不为空，结束日期将设置为该日期的最后时刻（23:59:59）；
     * 如果日期字符串为空，结束日期将设置为当前日期。
     *
     * @param sdf        用于解析和格式化日期的SimpleDateFormat对象。
     * @param endDateStr 代表结束日期的字符串，可以为空。
     * @return 返回计算得到的结束日期。
     * @throws ParseException 如果日期字符串的格式不匹配，将抛出此异常。
     */
    private Date getEndDate(SimpleDateFormat sdf, String endDateStr) throws ParseException {
        Date endDate;
        // 如果日期字符串不为空，解析并设置结束时间为该日期的最后时刻
        if (StringUtils.isNotBlank(endDateStr)) {
            endDate = sdf.parse(endDateStr + " 23:59:59");
        } else {
            // 如果日期字符串为空，结束日期设置为当前日期
            endDate = new Date();
        }
        return endDate;
    }


    /**
     * 根据传入的日期字符串和日期格式，获取开始日期。
     * 如果日期字符串不为空，则将其解析为指定格式的日期，时间为当日的凌晨0点。
     * 如果日期字符串为空，则返回当前年的1月1日的凌晨0点。
     *
     * @param sdf          日期格式化对象，用于解析和格式化日期字符串。
     * @param startDateStr 日期字符串，表示可能的开始日期。
     * @return 返回解析后的开始日期，如果输入为空则为当前年的1月1日。
     * @throws ParseException 如果日期字符串无法按照指定格式解析，则抛出此异常。
     */
    private Date getStartDate(SimpleDateFormat sdf, String startDateStr) throws ParseException {
        Date startDate;
        // 如果日期字符串不为空，将其解析为日期，并设置时间为当日的凌晨0点。
        if (StringUtils.isNotBlank(startDateStr)) {
            startDate = sdf.parse(startDateStr + " 00:00:00");
        } else {
            // 创建Calendar实例用于计算开始日期
            Calendar calendar = Calendar.getInstance();
            // 设置时间为当年的1月1日午夜
            calendar.set(Calendar.MONTH, Calendar.JANUARY); // 注意：月份是从0开始的，所以1月是0
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            // 获取设置后的日期时间
            startDate = calendar.getTime();
        }
        return startDate;
    }

}
