package org.jeecg.modules.system.app.service.impl;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.app.form.ClassPostponeForm;
import org.jeecg.modules.app.vo.*;
import org.jeecg.modules.system.app.dto.*;
import org.jeecg.modules.system.app.entity.*;
import org.jeecg.modules.system.app.mapper.*;
import org.jeecg.modules.system.app.service.IAppCoureseService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static org.jeecg.common.constant.CommonConstant.SC_INTERNAL_SERVER_ERROR_500;

/**
 * @Description: 课程/培训表
 * @Author: jeecg-boot
 * @Date: 2025-07-03
 * @Version: V1.0
 */
@Service
public class AppCoureseServiceImpl extends ServiceImpl<AppCoursesMapper, AppCourses> implements IAppCoureseService {
    @Resource
    private AppCoursesPriceRulesMapper priceRulesMapper;
    @Resource
    private AppSiteMapper siteMapper;
    @Resource
    private AppCategoryMapper categoryMapper;
    @Resource
    private AppCoursesVerificationRecordMapper appCoursesVerificationRecordMapper;
    @Resource
    private FamilyMembersMapper familyMembersMapper;
    @Resource
    private AppOrderMapper appOrderMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveWitchPriceRules(AppCoursesDTO appCoursesDTO) {
        AppCoursesCuDTO coursesCuDTO = appCoursesDTO.getCourses();
        if (null == coursesCuDTO.getCategoryId()) throw new JeecgBootException("请选择课程类别");
        AppSite site = siteMapper.selectOne(Wrappers.<AppSite>lambdaQuery().eq(AppSite::getOrgCode, coursesCuDTO.getOrgCode()));
        AppCourses appCourses = new AppCourses();
        BeanUtils.copyProperties(coursesCuDTO, appCourses);
        if (ObjUtil.isNotEmpty(site)){
            appCourses.setOrgCode(site.getOrgCode());
            appCourses.setTenantId(site.getTenantId());
            appCourses.setSiteId(site.getId());
        }

        appCourses.setUserId(coursesCuDTO.getUserId());
        appCourses.setAddressSiteId(coursesCuDTO.getAddressSiteId());
        List<AppCoursesRuleDTO> coursesRuleDTOS = appCoursesDTO.getPriceRulesList();
        //起止时间计算
        Optional<Date> minStartTime = coursesRuleDTOS.stream()
                .map(AppCoursesRuleDTO::getStartTime)
                .filter(Objects::nonNull)
                .min(Date::compareTo);

        Optional<Date> maxEndTime = coursesRuleDTOS.stream()
                .map(AppCoursesRuleDTO::getEndTime)
                .filter(Objects::nonNull)
                .max(Date::compareTo);
        appCourses.setStartTime(minStartTime.orElse(null));
        appCourses.setEndTime(maxEndTime.orElse(null));
        appCourses.setClassNum(coursesRuleDTOS.size());
        int saveCourseResult = baseMapper.insert(appCourses);
        if (saveCourseResult < 1) {
            throw new JeecgBootException("课程信息保存失败");
        }
        for (AppCoursesRuleDTO rule : coursesRuleDTOS) {
            AppCoursesPriceRules appCoursesPriceRules = new AppCoursesPriceRules();
            BeanUtils.copyProperties(rule, appCoursesPriceRules);
            appCoursesPriceRules.setCoursesId(appCourses.getId());
            appCoursesPriceRules.setOrgCode(appCourses.getOrgCode());
            appCoursesPriceRules.setTenantId(appCourses.getTenantId());
            int savePriceResult = priceRulesMapper.insert(appCoursesPriceRules); // 保证每个操作都在事务中
            if (savePriceResult < 1) {
                throw new JeecgBootException("课程价格规则保存失败");
            }
        }
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean editWitchPriceRules(AppCoursesDTO appCoursesDTO) {
        AppCoursesCuDTO coursesCuDTO = appCoursesDTO.getCourses();
        if (null == coursesCuDTO.getCategoryId()) throw new JeecgBootException("请选择课程类别");

        AppCourses appCourses = baseMapper.selectById(coursesCuDTO.getId());
        BeanUtils.copyProperties(coursesCuDTO, appCourses);
        appCourses.setAddressSiteId(coursesCuDTO.getAddressSiteId());
        List<AppCoursesRuleDTO> coursesRuleDTOS = appCoursesDTO.getPriceRulesList();
        //起止时间计算
        Optional<Date> minStartTime = coursesRuleDTOS.stream()
                .map(AppCoursesRuleDTO::getStartTime)
                .filter(Objects::nonNull)
                .min(Date::compareTo);

        Optional<Date> maxEndTime = coursesRuleDTOS.stream()
                .map(AppCoursesRuleDTO::getEndTime)
                .filter(Objects::nonNull)
                .max(Date::compareTo);
        appCourses.setStartTime(minStartTime.orElse(null));
        appCourses.setEndTime(maxEndTime.orElse(null));
        appCourses.setClassNum(coursesRuleDTOS.size());
        int updateResult = baseMapper.updateById(appCourses);
        if (updateResult < 1) {
            throw new JeecgBootException("课程信息保存失败");
        }

        //查历史本地数据
        List<AppCoursesPriceRules> coursesPriceRules = priceRulesMapper.selectList(Wrappers.lambdaQuery(AppCoursesPriceRules.class).eq(AppCoursesPriceRules::getCoursesId, appCourses.getId()));
        List<String> localList = coursesPriceRules.stream().map(AppCoursesPriceRules::getCoursesId).collect(Collectors.toList());
        //表单数据
        List<String> formList = coursesRuleDTOS.stream().filter(e -> ObjectUtils.isNotEmpty(e.getId())).map(AppCoursesRuleDTO::getId).collect(Collectors.toList());
        //有ID的做更新
        coursesRuleDTOS.stream().filter(e -> ObjectUtils.isNotEmpty(e.getId())).forEach(coursesRule -> {
            AppCoursesPriceRules appCoursesPriceRules = new AppCoursesPriceRules();
            BeanUtils.copyProperties(coursesRule, appCoursesPriceRules);
            priceRulesMapper.updateById(appCoursesPriceRules);
        });
        //差集直接做删除
        List<String> differ = getDifferListByMap(formList, localList);
        //修改状态
        for (String id : differ) {
            AppCoursesPriceRules appCoursesPriceRules = priceRulesMapper.selectById(id);
            if (ObjectUtils.isNotEmpty(appCoursesPriceRules)) {
                appCoursesPriceRules.setStatus(CommonConstant.STATUS_1_INT);
                priceRulesMapper.updateById(appCoursesPriceRules);
            }
        }
        //id为空做新增
        List<AppCoursesRuleDTO> nullList = coursesRuleDTOS.stream().filter(e -> ObjectUtils.isEmpty(e.getId())).collect(Collectors.toList());
        for (AppCoursesRuleDTO rule : nullList) {
            //做新增
            AppCoursesPriceRules appCoursesPriceRules = new AppCoursesPriceRules();
            BeanUtils.copyProperties(rule, appCoursesPriceRules);
            appCoursesPriceRules.setCoursesId(appCourses.getId());
            appCoursesPriceRules.setOrgCode(appCourses.getOrgCode());
            appCoursesPriceRules.setTenantId(appCourses.getTenantId());
            int savePriceResult = priceRulesMapper.insert(appCoursesPriceRules); // 保证每个操作都在事务中
            if (savePriceResult < 1) {
                throw new JeecgBootException("课程价格规则保存失败");
            }
        }
        return Boolean.TRUE;
    }


    public static List<String> getDifferListByMap(List<String> listA, List<String> listB) {
        List<String> differList = new ArrayList<>();
        Map<String, Integer> map = new HashMap<>();
        for (String strA : listA) {
            map.put(strA, 1);
        }
        for (String strB : listB) {
            Integer value = map.get(strB);
            if (value != null) {
                map.put(strB, ++value);
                continue;
            }
            map.put(strB, 1);
        }
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            if (entry.getValue() == 1) {
                differList.add(entry.getKey());
            }
        }
        return differList;
    }

    @Override
    public AppCoursesDTO queryWitchPriceRulesById(String id) {
        AppCourses dbCourse = baseMapper.selectById(id);
        if (null == dbCourse) throw new JeecgBootException("未找到对应数据", SC_INTERNAL_SERVER_ERROR_500);
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//        checkPermission(sysUser,dbCourse);
        List<AppCoursesPriceRules> priceRulesList =
                priceRulesMapper.selectList(Wrappers.<AppCoursesPriceRules>lambdaQuery().eq(AppCoursesPriceRules::getCoursesId, id));
        AppCoursesCuDTO coursesCuDTO = new AppCoursesCuDTO();
        BeanUtils.copyProperties(dbCourse, coursesCuDTO);
        List<AppCoursesRuleDTO> priceRules = new ArrayList<>();
        priceRulesList.forEach(rule -> {
            AppCoursesRuleDTO appCoursesRuleDTO = new AppCoursesRuleDTO();
            BeanUtils.copyProperties(rule, appCoursesRuleDTO);
            priceRules.add(appCoursesRuleDTO);
        });

        return new AppCoursesDTO(coursesCuDTO, priceRules);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteWitchPriceRulesById(String id) {
        AppCourses dbCourse = baseMapper.selectById(id);
        if (null == dbCourse) throw new JeecgBootException("未找到对应数据", SC_INTERNAL_SERVER_ERROR_500);
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//        checkPermission(sysUser,dbCourse);
        int deleteCourseResult = baseMapper.deleteById(id);
        if (deleteCourseResult < 1) {
            throw new JeecgBootException("课程信息删除失败", SC_INTERNAL_SERVER_ERROR_500);
        }
        int deletePriceResult = priceRulesMapper.delete(Wrappers.<AppCoursesPriceRules>lambdaQuery().eq(AppCoursesPriceRules::getCoursesId, id));
        if (deletePriceResult < 1) throw new JeecgBootException("课程价格规则删除失败", SC_INTERNAL_SERVER_ERROR_500);
        return Boolean.TRUE;
    }

    @Override
    public IPage<AppCoursesInfoPageDTO> queryWitchPriceRulesPage(AppCoursesPageDTO dto) {
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        dto.setOrgCode(loginUser.getOrgCode());
        Page<AppCourses> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        IPage<AppCoursesInfoPageDTO> resultPage = baseMapper.queryWitchPriceRulesPage(page, dto);

        resultPage.getRecords().forEach(r -> {
            String[] split = r.getCategoryId().split(",");
            List<String> ids = Arrays.stream(split).collect(Collectors.toList());

            Long count = priceRulesMapper.selectCount(Wrappers.<AppCoursesPriceRules>lambdaQuery().eq(AppCoursesPriceRules::getCoursesId, r.getId()));

            r.setTotalNum(Math.toIntExact(count));

            StringJoiner stringJoiner = new StringJoiner(",");

            for (String id : ids) {
                AppCategory category = categoryMapper.selectById(id);
                stringJoiner.add(category.getName());
            }
            r.setCategoryIds(stringJoiner.toString());
        });
        return resultPage;
    }

    @Override
    public List<AppSiteAddressDTO> queryAddressList() {
        List<AppSite> appSites = siteMapper.selectList(Wrappers.<AppSite>lambdaQuery().select(AppSite::getId, AppSite::getAddress));
        List<AppSiteAddressDTO> dtoList = Optional.ofNullable(appSites.stream().map(e -> {
            AppSiteAddressDTO appSiteAddressDTO = new AppSiteAddressDTO();
            appSiteAddressDTO.setSiteId(e.getId());
            appSiteAddressDTO.setAddress(e.getAddress());
            return appSiteAddressDTO;
        }).collect(Collectors.toList())).orElse(List.of());
        return dtoList;
    }

    @Override
    public VerifyCourseInfoVO getCourseInfo(String courseId) {

        VerifyCourseInfoVO verifyCourseInfoVO = new VerifyCourseInfoVO();

        List<VerifyCourseInfoDTO> verifyCourseInfoDTOList = new ArrayList<>();
        List<CoursesPriceRulesVO> voList = new ArrayList<>();

        List<AppCoursesPriceRules> priceRulesList = priceRulesMapper.selectList(Wrappers.lambdaQuery(AppCoursesPriceRules.class).eq(AppCoursesPriceRules::getCoursesId, courseId));
        for (AppCoursesPriceRules priceRules : priceRulesList) {
            CoursesPriceRulesVO coursesPriceRulesVO = new CoursesPriceRulesVO();
            coursesPriceRulesVO.setId(priceRules.getId());
            coursesPriceRulesVO.setCoursesId(priceRules.getCoursesId());
            coursesPriceRulesVO.setName(priceRules.getName());
            coursesPriceRulesVO.setStartTime(priceRules.getStartTime());
            coursesPriceRulesVO.setEndTime(priceRules.getEndTime());
            coursesPriceRulesVO.setCoursesType(priceRules.getCoursesType());

            List<AppCoursesVerificationRecord> verificationRecordList = appCoursesVerificationRecordMapper
                    .selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery().eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, priceRules.getId()));
            //共计
            coursesPriceRulesVO.setTotalNum(verificationRecordList.size());
            //延期
            long postponeNum = verificationRecordList.stream().filter(e -> e.getOrPostpone() == 1).count();
            coursesPriceRulesVO.setPostponeNum((int) postponeNum);
            //已核验
            long writtenOffNum = verificationRecordList.stream().filter(e -> e.getVerifyStatus() == 1).count();
            coursesPriceRulesVO.setWrittenOffNum((int) writtenOffNum);
            //未核验
            long unwrittenOffNum = verificationRecordList.stream().filter(e -> e.getVerifyStatus() == 0 && e.getOrPostpone() == 0).count();
            coursesPriceRulesVO.setUnwrittenOffNum((int) unwrittenOffNum);

            //判断是否为当日数据
            LocalDate today = LocalDate.now();
            LocalDate localDate = priceRules.getStartTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
            if (today.isAfter(localDate)) {
                verifyCourseInfoVO.setPriceRulesVO(coursesPriceRulesVO);
            } else {
                voList.add(coursesPriceRulesVO);
            }
        }
        Map<Integer, List<CoursesPriceRulesVO>> map = voList.stream().collect(Collectors.groupingBy(CoursesPriceRulesVO::getCoursesType));
        if (!map.isEmpty()) {
            map.keySet().forEach(key -> {
                VerifyCourseInfoDTO verifyCourseInfoDTO = new VerifyCourseInfoDTO();
                verifyCourseInfoDTO.setCourseType(key).setVoList(map.get(key));

                verifyCourseInfoDTOList.add(verifyCourseInfoDTO);
            });
        }
        verifyCourseInfoVO.setVerifyCourseInfoVOList(verifyCourseInfoDTOList);
        return verifyCourseInfoVO;
    }

    /**
     * 临时约课
     *
     * @param coursePriceRulesId
     * @param familyMemberId
     * @return
     */
    @Override
    public Boolean temporaryCourse(String coursePriceRulesId, String familyMemberId) {

        AppCoursesPriceRules appCoursesPriceRules = priceRulesMapper.selectById(coursePriceRulesId);

        FamilyMembers familyMembers = familyMembersMapper.selectById(familyMemberId);

        if (ObjUtil.isEmpty(familyMembers)) {
            throw new JeecgBootException("当前用户不存在，请确认后重新提交");
        }

        //判断是否已存在
        List<AppCoursesVerificationRecord> verificationRecords =
                appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery()
                        .eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, coursePriceRulesId)
                        .eq(AppCoursesVerificationRecord::getUseUserId,familyMemberId)
                );
        if (ObjUtil.isNotEmpty(verificationRecords)) {
            throw new JeecgBootException(familyMembers.getFullName()+"已经在课程中,请确认后重新提交");
        }

        AppCoursesVerificationRecord appCoursesVerificationRecord = new AppCoursesVerificationRecord();
        appCoursesVerificationRecord.setCoursesId(appCoursesPriceRules.getCoursesId());
        appCoursesVerificationRecord.setCoursesPriceRuleId(appCoursesPriceRules.getId());
        appCoursesVerificationRecord.setCoursesName(appCoursesPriceRules.getName());
        appCoursesVerificationRecord.setCoursesStartTime(appCoursesPriceRules.getStartTime());
        appCoursesVerificationRecord.setCoursesEndTime(appCoursesPriceRules.getEndTime());
        appCoursesVerificationRecord.setUseUserId(familyMemberId);
        appCoursesVerificationRecord.setUseUserName(familyMembers.getFullName());
        appCoursesVerificationRecord.setVerifyStatus(0);
        appCoursesVerificationRecord.setOrPostpone(0);
        appCoursesVerificationRecord.setCoursesType(0);

        int insert = appCoursesVerificationRecordMapper.insert(appCoursesVerificationRecord);
        if (insert < 1) throw new JeecgBootException("临时约课创建失败", SC_INTERNAL_SERVER_ERROR_500);
        return Boolean.TRUE;
    }

    @Override
    public List<FamilyUserVO> getClassPostponeUsers(String coursePriceRulesId) {

        List<AppCoursesVerificationRecord> verificationRecordList = appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery().eq(AppCoursesVerificationRecord::getCoursesId, coursePriceRulesId));

        return verificationRecordList.stream().map(e -> {
            FamilyUserVO familyUserVO = new FamilyUserVO();
            familyUserVO.setFamilyUserId(e.getUseUserId()).setFamilyUserName(e.getCoursesName()).setFamilyUserImage(e.getUseUserImage());
            return familyUserVO;
        }).collect(Collectors.toList());
    }

    @Override
    public Boolean classPostpone(ClassPostponeForm form) {

        AppOrder appOrder = appOrderMapper.selectById(form.getOrderId());
        //补课课时
        AppCoursesPriceRules appCoursesPriceRules = priceRulesMapper.selectById(form.getCoursePriceRulesId());
        //设置为延期状态
        appCoursesPriceRules.setClassStatus(CommonConstant.STATUS_1_INT);
        List<AppCoursesVerificationRecord> verificationRecordList = appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery().eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, form.getCoursePriceRulesId()));
        //所有记录修改为延期
        for (AppCoursesVerificationRecord appCoursesVerificationRecord : verificationRecordList) {
            appCoursesVerificationRecord
                    .setOrPostpone(CommonConstant.STATUS_1_INT)
                    .setPostponeReason(form.getPostponeReason());
            appCoursesVerificationRecordMapper.updateById(appCoursesVerificationRecord);
        }

        for (FamilyUserVO familyUserVO : form.getFamilyUserVOList()) {
            AppCoursesVerificationRecord verificationRecord = new AppCoursesVerificationRecord();
            verificationRecord.setOrderId(appOrder.getId());
            verificationRecord.setOrderCode(appOrder.getOrderCode());
            verificationRecord.setCoursesId(appOrder.getProductIds());
            verificationRecord.setCoursesPriceRuleId(appCoursesPriceRules.getId());
            verificationRecord.setCoursesName(appCoursesPriceRules.getName());
            verificationRecord.setCoursesStartTime(appCoursesPriceRules.getStartTime());
            verificationRecord.setCoursesEndTime(appCoursesPriceRules.getEndTime());
            verificationRecord.setUseUserId(familyUserVO.getFamilyUserId());
            verificationRecord.setUseUserName(familyUserVO.getFamilyUserName());
            verificationRecord.setUseUserImage(familyUserVO.getFamilyUserImage());
            verificationRecord.setVerifyStatus(CommonConstant.STATUS_1_INT);
            verificationRecord.setCoursesType(CommonConstant.STATUS_1_INT);
            appCoursesVerificationRecordMapper.insert(verificationRecord);
        }
        return Boolean.TRUE;
    }

    @Override
    public IPage<AppCoursesPageVO> getPageCourse(Page<AppCoursesPageVO> page, String orgCode, String userId) {
        return baseMapper.getPageCourse(page,orgCode,userId);
    }

    /**
     * 校验权限
     *
     * @param loginUser
     * @param course
     */
    private void checkPermission(LoginUser loginUser, AppCourses course) {
        if (!loginUser.getOrgCode().equals(course.getOrgCode()))
            throw new JeecgBootException("无权限操作", SC_INTERNAL_SERVER_ERROR_500);
    }
}
