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

import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.enums.DeleteFlag;
import com.core.common.utils.*;
import com.core.common.utils.poi.ExcelUtil;
import com.openhis.administration.domain.Patient;
import com.openhis.administration.domain.PatientStudent;
import com.openhis.administration.service.IPatientService;
import com.openhis.administration.service.IPatientStudentService;
import com.openhis.common.enums.AssignSeqEnum;
import com.openhis.common.enums.PhysicalExamResult;
import com.openhis.common.enums.StudentStatus;
import com.openhis.common.utils.CommonUtil;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.common.utils.IdCardUtil;
import com.openhis.web.nenu.appservice.IGfStudentListAppService;
import com.openhis.web.nenu.dto.GfStudentListDto;
import com.openhis.web.nenu.dto.GfStudentListImportDto;
import com.openhis.web.nenu.mapper.GfStudentListAppMapper;

/**
 * 公费医疗-学生名单管理 AppServiceImpl
 *
 * @author Thanking
 * @date 2025-10-21
 */
@Service
public class GfStudentListAppServiceImpl implements IGfStudentListAppService {

    @Autowired
    private IPatientStudentService patientStudentService;
    @Autowired
    private IPatientService patientService;
    @Autowired
    private GfStudentListAppMapper gfStudentListAppMapper;
    @Autowired
    private AssignSeqUtil assignSeqUtil;

    /**
     * 查询学生名单分页
     *
     * @param searchParam 查询参数
     * @param searchKey 模糊查询关键字
     * @param pageNo 页码
     * @param pageSize 行数
     * @return 学生名单分页
     */
    @Override
    public R<IPage<GfStudentListDto>> getPage(GfStudentListDto searchParam, String searchKey, Integer pageNo,
        Integer pageSize) {
        // 构造查询条件
        QueryWrapper<GfStudentListDto> queryWrapper = HisQueryUtils.buildQueryWrapper(searchParam, searchKey,
            new HashSet<>(Set.of("name", "py_str", "wb_str", "student_id", "id_number")), null);
        // 查询学生名单分页
        IPage<GfStudentListDto> page =
            gfStudentListAppMapper.selectGfStudentListPage(new Page<>(pageNo, pageSize), queryWrapper);
        return R.ok(page);
    }

    /**
     * 查询学生名单详情
     *
     * @param id ID
     * @return 学生名单详情
     */
    @Override
    public R<GfStudentListDto> getDetail(Long id) {
        // 查询学生名单详情
        PatientStudent patientStudent = patientStudentService.getById(id);
        if (patientStudent == null) {
            return R.fail();
        }
        // 返回Dto赋值
        GfStudentListDto gfStudentListDto = new GfStudentListDto().setId(patientStudent.getId())
            .setName(patientStudent.getName()).setGender(patientStudent.getGender()).setAge(patientStudent.getAge())
            .setStudentId(patientStudent.getStudentId()).setIdNumber(patientStudent.getIdNumber())
            .setPhone(patientStudent.getPhone()).setCollege(patientStudent.getCollege())
            .setMajor(patientStudent.getMajor()).setEducationLevel(patientStudent.getEducationLevel())
            .setEnrollmentDate(patientStudent.getEnrollmentDate()).setGraduationDate(patientStudent.getGraduationDate())
            .setGrade(patientStudent.getGrade()).setStudyMode(patientStudent.getStudyMode())
            .setStudentStatus(patientStudent.getStudentStatus())
            .setPhysicalExamResult(patientStudent.getPhysicalExamResult()).setCounselor(patientStudent.getCounselor())
            .setCounselorPhone(patientStudent.getCounselorPhone()).setPatientId(patientStudent.getPatientId());
        return R.ok(gfStudentListDto);
    }

    /**
     * 添加学生名单
     *
     * @param gfStudentListDto 学生名单Dto
     * @return 结果
     */
    @Override
    public R<?> add(GfStudentListDto gfStudentListDto) {
        // 学号重复验证
        List<PatientStudent> sameStudentIdStudents = patientStudentService.list(
            new LambdaQueryWrapper<PatientStudent>().eq(PatientStudent::getStudentId, gfStudentListDto.getStudentId())
                .eq(PatientStudent::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()));
        if (!sameStudentIdStudents.isEmpty()) {
            return R.fail("学号" + gfStudentListDto.getStudentId() + "在系统中已存在");
        }
        // 学生信息重复校验
        List<PatientStudent> sameIdNumberStudents = patientStudentService.list(
            new LambdaQueryWrapper<PatientStudent>().eq(PatientStudent::getIdNumber, gfStudentListDto.getIdNumber())
                .eq(PatientStudent::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()));
        Long existingPatientId = null;
        if (!sameIdNumberStudents.isEmpty()) {
            for (PatientStudent ps : sameIdNumberStudents) {
                if (!ps.getEnrollmentDate().after(gfStudentListDto.getGraduationDate())
                    && !ps.getGraduationDate().before(gfStudentListDto.getEnrollmentDate())) {
                    return R.fail("该身份证在系统中已录入过学生信息，此次录入的入校离校时间与既存数据有重叠，请确认");
                }
            }
            existingPatientId = sameIdNumberStudents.get(0).getPatientId();
        }
        // 从身份证中获取生日和年龄
        Date birthDate = null;
        Integer age = null;
        try {
            birthDate = IdCardUtil.extractBirthdayFromIdCard(gfStudentListDto.getIdNumber());
            age = IdCardUtil.calculateAgeFromIdCard(gfStudentListDto.getIdNumber());
        } catch (Exception ignored) {
        }
        // 生成姓名的拼音码和五笔码
        String pyStr = ChineseConvertUtils.toPinyinFirstLetter(gfStudentListDto.getName());
        String wbStr = ChineseConvertUtils.toWBFirstLetter(gfStudentListDto.getName());
        // 系统中不存在历史学生信息时
        if (existingPatientId == null) {
            // 判断患者信息是否有重复
            List<Patient> sameIdNumberPatients = patientService
                .list(new LambdaQueryWrapper<Patient>().eq(Patient::getIdCard, gfStudentListDto.getIdNumber())
                    .eq(Patient::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()));
            if (!sameIdNumberPatients.isEmpty()) {
                // 已存在则取存在的
                existingPatientId = sameIdNumberPatients.get(0).getId();
            } else {
                // 不存在则新建患者
                Patient patient =
                    new Patient().setBusNo(assignSeqUtil.getSeq(AssignSeqEnum.PATIENT_NUM.getPrefix(), 10))
                        .setName(gfStudentListDto.getName()).setGenderEnum(gfStudentListDto.getGender())
                        .setBirthDate(birthDate).setPhone(gfStudentListDto.getPhone())
                        .setIdCard(gfStudentListDto.getIdNumber()).setPyStr(pyStr).setWbStr(wbStr)
                        .setOrganizationId(SecurityUtils.getLoginUser().getOrgId());
                patientService.save(patient);
                existingPatientId = patient.getId();
            }
        }
        // 创建学生信息
        PatientStudent patientStudent = new PatientStudent().setName(gfStudentListDto.getName()).setPyStr(pyStr)
            .setWbStr(wbStr).setGender(gfStudentListDto.getGender()).setAge(age)
            .setStudentId(gfStudentListDto.getStudentId()).setIdNumber(gfStudentListDto.getIdNumber())
            .setPhone(gfStudentListDto.getPhone()).setCollege(gfStudentListDto.getCollege())
            .setMajor(gfStudentListDto.getMajor()).setEducationLevel(gfStudentListDto.getEducationLevel())
            .setEnrollmentDate(gfStudentListDto.getEnrollmentDate())
            .setGraduationDate(gfStudentListDto.getGraduationDate()).setGrade(gfStudentListDto.getGrade())
            .setStudyMode(gfStudentListDto.getStudyMode()).setStudentStatus(gfStudentListDto.getStudentStatus())
            .setPhysicalExamResult(gfStudentListDto.getPhysicalExamResult())
            .setCounselor(gfStudentListDto.getCounselor()).setCounselorPhone(gfStudentListDto.getCounselorPhone())
            .setPatientId(existingPatientId);
        patientStudentService.save(patientStudent);
        return R.ok();
    }

    /**
     * 编辑学生名单
     *
     * @param gfStudentListDto 学生名单Dto
     * @return 结果
     */
    @Override
    public R<?> edit(GfStudentListDto gfStudentListDto) {
        // 查询学生信息
        PatientStudent patientStudent = patientStudentService.getById(gfStudentListDto.getId());
        if (patientStudent == null) {
            return R.fail("学生信息不存在");
        }
        // 从身份证中获取生日和年龄
        Date birthDate = null;
        Integer age = null;
        try {
            birthDate = IdCardUtil.extractBirthdayFromIdCard(gfStudentListDto.getIdNumber());
            age = IdCardUtil.calculateAgeFromIdCard(gfStudentListDto.getIdNumber());
        } catch (Exception ignored) {
        }
        // 生成姓名的拼音码和五笔码
        String pyStr = ChineseConvertUtils.toPinyinFirstLetter(gfStudentListDto.getName());
        String wbStr = ChineseConvertUtils.toWBFirstLetter(gfStudentListDto.getName());
        // 更新学生信息
        patientStudentService.update(new LambdaUpdateWrapper<PatientStudent>()
            .set(PatientStudent::getName, gfStudentListDto.getName()).set(PatientStudent::getPyStr, pyStr)
            .set(PatientStudent::getWbStr, wbStr).set(PatientStudent::getGender, gfStudentListDto.getGender())
            .set(PatientStudent::getAge, age).set(PatientStudent::getStudentId, gfStudentListDto.getStudentId())
            .set(PatientStudent::getIdNumber, gfStudentListDto.getIdNumber())
            .set(PatientStudent::getPhone, gfStudentListDto.getPhone())
            .set(PatientStudent::getCollege, gfStudentListDto.getCollege())
            .set(PatientStudent::getMajor, gfStudentListDto.getMajor())
            .set(PatientStudent::getEducationLevel, gfStudentListDto.getEducationLevel())
            .set(PatientStudent::getEnrollmentDate, gfStudentListDto.getEnrollmentDate())
            .set(PatientStudent::getGraduationDate, gfStudentListDto.getGraduationDate())
            .set(PatientStudent::getGrade, gfStudentListDto.getGrade())
            .set(PatientStudent::getStudyMode, gfStudentListDto.getStudyMode())
            .set(PatientStudent::getStudentStatus, gfStudentListDto.getStudentStatus())
            .set(PatientStudent::getPhysicalExamResult, gfStudentListDto.getPhysicalExamResult())
            .set(PatientStudent::getCounselor, gfStudentListDto.getCounselor())
            .set(PatientStudent::getCounselorPhone, gfStudentListDto.getCounselorPhone())
            .eq(PatientStudent::getId, gfStudentListDto.getId()));
        // 同步更新患者信息
        patientService.update(new Patient(), new LambdaUpdateWrapper<Patient>()
            .set(Patient::getName, gfStudentListDto.getName()).set(Patient::getPyStr, pyStr)
            .set(Patient::getWbStr, wbStr).set(Patient::getGenderEnum, gfStudentListDto.getGender())
            .set(Patient::getBirthDate, birthDate).set(Patient::getPhone, gfStudentListDto.getPhone())
            .set(Patient::getIdCard, gfStudentListDto.getIdNumber()).eq(Patient::getId, patientStudent.getPatientId()));
        return R.ok();
    }

    /**
     * 删除学生名单
     *
     * @param id ID
     * @return 结果
     */
    @Override
    public R<?> delete(Long id) {
        patientStudentService.update(new LambdaUpdateWrapper<PatientStudent>()
            .set(PatientStudent::getDeleteFlag, DeleteFlag.DELETED.getCode()).eq(PatientStudent::getId, id));
        return R.ok();
    }

    /**
     * 导入学生名单
     *
     * @param file 文件
     * @return 结果
     */
    @Override
    public R<?> importData(MultipartFile file) {
        // 读取文件
        R<List<GfStudentListImportDto>> readResult =
            CommonUtil.readImportedExcelFile(file, GfStudentListImportDto.class);
        if (R.SUCCESS != readResult.getCode()) {
            return readResult;
        }
        List<GfStudentListImportDto> importDtoList = readResult.getData();
        // 导入信息校验
        R<?> validateResult = validateImportDtoList(importDtoList);
        if (R.SUCCESS != validateResult.getCode()) {
            return validateResult;
        }
        // 查询机构ID
        Long orgId = SecurityUtils.getLoginUser().getOrgId();
        for (GfStudentListImportDto importDto : importDtoList) {
            // 从身份证中获取生日和年龄
            Date birthDate = null;
            Integer age = null;
            try {
                birthDate = IdCardUtil.extractBirthdayFromIdCard(importDto.getIdNumber());
                age = IdCardUtil.calculateAgeFromIdCard(importDto.getIdNumber());
            } catch (Exception ignored) {
            }
            // 生成姓名的拼音码和五笔码
            String pyStr = ChineseConvertUtils.toPinyinFirstLetter(importDto.getName());
            String wbStr = ChineseConvertUtils.toWBFirstLetter(importDto.getName());
            // 患者未创建时，创建患者
            if (importDto.getPatientId() == null) {
                Patient patient =
                    new Patient().setBusNo(assignSeqUtil.getSeq(AssignSeqEnum.PATIENT_NUM.getPrefix(), 10))
                        .setName(importDto.getName()).setGenderEnum(CommonUtil.tryParseInt(importDto.getGender()))
                        .setBirthDate(birthDate).setPhone(importDto.getPhone()).setIdCard(importDto.getIdNumber())
                        .setPyStr(pyStr).setWbStr(wbStr).setOrganizationId(orgId);
                patientService.save(patient);
                importDto.setPatientId(patient.getId());
            }
            // 创建学生信息
            PatientStudent patientStudent = new PatientStudent().setName(importDto.getName()).setPyStr(pyStr)
                .setWbStr(wbStr).setGender(CommonUtil.tryParseInt(importDto.getGender())).setAge(age)
                .setStudentId(importDto.getStudentId()).setIdNumber(importDto.getIdNumber())
                .setPhone(importDto.getPhone()).setCollege(importDto.getCollege()).setMajor(importDto.getMajor())
                .setEducationLevel(CommonUtil.tryParseInt(importDto.getEducationLevel()))
                .setEnrollmentDate(importDto.getEnrollmentDate()).setGraduationDate(importDto.getGraduationDate())
                .setGrade(importDto.getGrade()).setStudyMode(CommonUtil.tryParseInt(importDto.getStudyMode()))
                // 在校状态：在校
                .setStudentStatus(StudentStatus.IN_SCHOOL.getValue())
                // 体检结果：体检合格
                .setPhysicalExamResult(PhysicalExamResult.EXAMINATION_PASSED.getValue())
                .setCounselor(importDto.getCounselor()).setCounselorPhone(importDto.getCounselorPhone())
                .setPatientId(importDto.getPatientId());
            patientStudentService.save(patientStudent);
        }
        return R.ok();
    }

    /**
     * 获取导入模板
     *
     * @param response 响应
     */
    @Override
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<GfStudentListImportDto> util = new ExcelUtil<>(GfStudentListImportDto.class);
        util.importTemplateExcel(response, "学生名单");
    }

    /**
     * 导入信息校验
     *
     * @param importDtoList 学生名单导入数据列表
     */
    private R<?> validateImportDtoList(List<GfStudentListImportDto> importDtoList) {
        // 字段校验（必填及数值类型）
        List<String> fieldValidateMsgList = new ArrayList<>();
        for (int i = 0; i < importDtoList.size(); i++) {
            GfStudentListImportDto importDto = importDtoList.get(i);
            importDto.setLineNumber(i + 2);
            List<String> lineValidateMsgList = new ArrayList<>();
            if (StringUtils.isEmpty(importDto.getName())) {
                lineValidateMsgList.add("姓名必填");
            }
            if (StringUtils.isEmpty(importDto.getGender())) {
                lineValidateMsgList.add("性别必填");
            }
            if (StringUtils.isEmpty(importDto.getStudentId())) {
                lineValidateMsgList.add("学号必填");
            }
            if (StringUtils.isEmpty(importDto.getIdNumber())) {
                lineValidateMsgList.add("身份证号必填");
            }
            if (StringUtils.isEmpty(importDto.getPhone())) {
                lineValidateMsgList.add("电话必填");
            }
            if (StringUtils.isEmpty(importDto.getCollege())) {
                lineValidateMsgList.add("学院必填");
            }
            if (StringUtils.isEmpty(importDto.getMajor())) {
                lineValidateMsgList.add("专业必填");
            }
            if (StringUtils.isEmpty(importDto.getEducationLevel())) {
                lineValidateMsgList.add("学历层次必填");
            }
            if (StringUtils.isEmpty(importDto.getEnrollmentDateStr())) {
                lineValidateMsgList.add("入校时间必填");
            }
            try {
                importDto.setEnrollmentDate(DateUtils.parseDate(importDto.getEnrollmentDateStr()));
            } catch (Exception e) {
                lineValidateMsgList.add("入校时间格式错误");
            }
            if (StringUtils.isEmpty(importDto.getGraduationDateStr())) {
                lineValidateMsgList.add("离校时间必填");
            }
            try {
                importDto.setGraduationDate(DateUtils.parseDate(importDto.getGraduationDateStr()));
            } catch (DateTimeParseException e) {
                lineValidateMsgList.add("离校时间格式错误");
            }
            if (StringUtils.isEmpty(importDto.getGrade())) {
                lineValidateMsgList.add("年级必填");
            }
            if (StringUtils.isEmpty(importDto.getStudyMode())) {
                lineValidateMsgList.add("学习形式必填");
            }
            if (StringUtils.isEmpty(importDto.getCounselor())) {
                lineValidateMsgList.add("辅导员必填");
            }
            if (StringUtils.isEmpty(importDto.getCounselorPhone())) {
                lineValidateMsgList.add("辅导员电话必填");
            }
            if (!lineValidateMsgList.isEmpty()) {
                fieldValidateMsgList
                    .add("■ 第" + importDto.getLineNumber() + "行：" + String.join("，", lineValidateMsgList) + "；");
            }
        }
        if (!fieldValidateMsgList.isEmpty()) {
            return R.fail("导入失败！学生名单填写有误：" + String.join(" ", fieldValidateMsgList) + " ■ ※如遇到模板中不存在的字段，请重新下载模板");
        }
        // 重复校验（文件行重复）
        List<String> lineRepeatedValidateMsgList = new ArrayList<>();
        Map<String, List<GfStudentListImportDto>> fileSameStudentIdMap =
            importDtoList.stream().collect(Collectors.groupingBy(GfStudentListImportDto::getStudentId));
        for (Map.Entry<String, List<GfStudentListImportDto>> entry : fileSameStudentIdMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                lineRepeatedValidateMsgList
                    .add("■ 第" + entry.getValue().stream().map(GfStudentListImportDto::getLineNumber).sorted()
                        .map(Object::toString).collect(Collectors.joining(",")) + "行的学号重复；");
            }
        }
        Map<String, List<GfStudentListImportDto>> fileSameIdNumberMap =
            importDtoList.stream().collect(Collectors.groupingBy(GfStudentListImportDto::getIdNumber));
        for (Map.Entry<String, List<GfStudentListImportDto>> entry : fileSameIdNumberMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                lineRepeatedValidateMsgList
                    .add("■ 第" + entry.getValue().stream().map(GfStudentListImportDto::getLineNumber).sorted()
                        .map(Object::toString).collect(Collectors.joining(",")) + "行的身份证号重复；");
            }
        }
        if (!lineRepeatedValidateMsgList.isEmpty()) {
            return R.fail("导入失败！文件中存在重复数据：" + String.join(" ", lineRepeatedValidateMsgList));
        }
        // 重复校验（文件与数据库重复）
        List<String> dbRepeatedValidateMsgList = new ArrayList<>();
        for (GfStudentListImportDto importDto : importDtoList) {
            List<PatientStudent> sameStudentIdStudents = patientStudentService.list(
                new LambdaQueryWrapper<PatientStudent>().eq(PatientStudent::getStudentId, importDto.getStudentId())
                    .eq(PatientStudent::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()));
            if (!sameStudentIdStudents.isEmpty()) {
                dbRepeatedValidateMsgList.add("■ 第" + importDto.getLineNumber() + "行的学号在系统中已存在；");
            }
            List<PatientStudent> sameIdNumberStudents = patientStudentService
                .list(new LambdaQueryWrapper<PatientStudent>().eq(PatientStudent::getIdNumber, importDto.getIdNumber())
                    .eq(PatientStudent::getDeleteFlag, DeleteFlag.NOT_DELETED.getCode()));
            if (!sameIdNumberStudents.isEmpty()) {
                for (PatientStudent ps : sameIdNumberStudents) {
                    if (!ps.getEnrollmentDate().after(importDto.getGraduationDate())
                        && !ps.getGraduationDate().before(importDto.getEnrollmentDate())) {
                        dbRepeatedValidateMsgList
                            .add("■ 第" + importDto.getLineNumber() + "行的身份证在系统中已录入过学生信息，此次录入的入校离校时间与既存数据有重叠，请确认；");
                    }
                }
                importDto.setPatientId(sameIdNumberStudents.get(0).getPatientId());
            }
        }
        if (!dbRepeatedValidateMsgList.isEmpty()) {
            return R.fail("导入失败！系统中存在重复数据：" + String.join(" ", dbRepeatedValidateMsgList));
        }
        return R.ok();
    }

}
