package com.yida.data.mall.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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 com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.constant.StringConstant;
import com.yida.data.common.core.entity.mall.*;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.enums.BillStatusEnum;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.mall.dto.BillOrderSelectPageDTO;
import com.yida.data.mall.dto.BillSaveDTO;
import com.yida.data.mall.dto.BillSelectPageDTO;
import com.yida.data.mall.mapper.EduBillMapper;
import com.yida.data.mall.service.*;
import com.yida.data.mall.vo.*;
import com.yida.data.system.feign.RemoteUserService;
import com.yida.data.user.feign.RemoteStudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 缴费账单表 Service实现
 *
 * @author ZYJ
 * @date 2021-12-24 09:47:02
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class EduBillServiceImpl extends ServiceImpl
        <EduBillMapper, EduBill> implements EduBillService {

    private final CommonService commonService;
    private final RemoteUserService remoteUserService;
    private final RemoteStudentService remoteStudentService;

    private final EduBillItemService eduBillItemService;
    private final EduBillStudentService eduBillStudentService;
    private final EduBillItemSubService eduBillItemSubService;
    private final EduBillOrderService eduBillOrderService;
    private final EduBillOrderItemService eduBillOrderItemService;
    private final EduBillOrderItemSubService eduBillOrderItemSubService;

    @Lazy
    @Resource
    private H5EduBillService h5EduBillService;

    @Override
    public IPage<BillSelectPageVO> listBillPage(BillSelectPageDTO billSelectPageDTO) {
        // 登陆用户信息
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        // TODO 2021/12/24 此处暂时只有学校, 后续处理其它角色类型
        billSelectPageDTO.setDeptId(currentUser.getDeptId());

        IPage<BillSelectPageVO> page = baseMapper.listBillPage(billSelectPageDTO.toPage(), billSelectPageDTO);
        // 查询学生id信息
        EduStudent eduStudent = new EduStudent();
        eduStudent.setSchoolId(currentUser.getDeptId());
        List<Long> studentIds = remoteStudentService.listBaseStudentIds(eduStudent).getData();
        page.getRecords().forEach(billSelectPageVO -> {
            // 查询部门数据
            billSelectPageVO.setDeptName(commonService.getDept(billSelectPageVO.getDeptId()).getDeptName());
            // 创建人
            billSelectPageVO.setCreateName(remoteUserService.getInfoById(billSelectPageVO.getCreateId()).getData().getNickname());
            // 账单总人数
            long totalNumber = CollUtil.isNotEmpty(studentIds) ? eduBillStudentService.count(new LambdaQueryWrapper<>(new EduBillStudent())
                    .eq(EduBillStudent::getBillId, billSelectPageVO.getId())
                    .in(EduBillStudent::getStudentId, studentIds)) : 0;
            billSelectPageVO.setTotalNumber(totalNumber);
            // 缴费人数 缴费金额大于0
            if (totalNumber > 0) {
                billSelectPageVO.setPayNumber(eduBillOrderService.sumPayStudentNumber(billSelectPageVO.getId()));
            }
        });
        return page;
    }

    @Override
    public BillInfoVO getBillInfo(Long billId) {
        EduBill eduBill = getById(billId);
        BillInfoVO billInfoVO = new BillInfoVO();
        Optional.ofNullable(eduBill).ifPresent(bill -> {
            BeanUtils.copyProperties(eduBill, billInfoVO);
            // 学校名称
            billInfoVO.setDeptName(commonService.getDept(bill.getDeptId()).getDeptName());
            // 创建人
            billInfoVO.setCreateName(remoteUserService.getInfoById(bill.getCreateId()).getData().getNickname());

            // 查询缴费项目信息
            List<EduBillItem> itemList = eduBillItemService.list(
                    new LambdaQueryWrapper<>(new EduBillItem()).eq(EduBillItem::getBillId, billId)
                            .orderByAsc(EduBillItem::getId));
            billInfoVO.setItemList(itemList.stream().map(eduBillItem -> {
                BillItemInfoVO billItemInfoVO = new BillItemInfoVO();
                BeanUtils.copyProperties(eduBillItem, billItemInfoVO);
                // 判断家庭类型
                if (StringUtils.isNotBlank(eduBillItem.getFamilyType())) {
                    billItemInfoVO.setFamilyType(eduBillItem.getFamilyType().split(","));
                } else {
                    billItemInfoVO.setFamilyType(new String[]{});
                }
                // 查询选项数据
                List<EduBillItemSub> subItemList = eduBillItemSubService.list(
                        new LambdaQueryWrapper<>(new EduBillItemSub()).eq(EduBillItemSub::getItemId, eduBillItem.getId())
                                .orderByAsc(EduBillItemSub::getId));

                billItemInfoVO.setSubItemList(subItemList.stream().map(subItem -> {
                    BillSubItemInfoVO billSubItemInfoVO = new BillSubItemInfoVO();
                    BeanUtils.copyProperties(subItem, billSubItemInfoVO);
                    return billSubItemInfoVO;
                }).collect(Collectors.toList()));

                return billItemInfoVO;
            }).collect(Collectors.toList()));
            // 查询学生信息
            EduStudent eduStudent = new EduStudent();
            eduStudent.setSchoolId(FebsUtil.getDeptId());
            List<EduStudent> studentList = remoteStudentService.listBaseStudent(eduStudent).getData();
            // 学生id
            List<Long> studentIdList = studentList.stream().map(EduStudent::getId).collect(Collectors.toList());
            // 学生分组
            Map<Long, List<EduStudent>> studentMap = studentList.stream().collect(Collectors.groupingBy(EduStudent::getId));
            // 查询账单学生
            List<EduBillStudent> billStudentList = eduBillStudentService.list(
                    new LambdaQueryWrapper<>(new EduBillStudent())
                            .eq(EduBillStudent::getBillId, billId)
                            .in(EduBillStudent::getStudentId, studentIdList)
            );
            billInfoVO.setAchieveList(billStudentList.stream().map(eduBillStudent -> {
                BillStudentInfoVO billStudentInfoVO = new BillStudentInfoVO();
                // 匹配学生信息
                EduStudent student = studentMap.get(eduBillStudent.getStudentId()).get(0);
                BeanUtils.copyProperties(student, billStudentInfoVO);
                // 设置选中信息
                billStudentInfoVO.setDeptId(eduBillStudent.getDeptId());
                billStudentInfoVO.setDeptName(eduBillStudent.getDeptName());
                billStudentInfoVO.setStudentName(eduBillStudent.getStudentName());
                // 判断是否禁用
                boolean disabled = !(Objects.isNull(bill.getBillStartDate()) || bill.getBillStartDate().isAfter(LocalDateTime.now()));
                billStudentInfoVO.setDisabled(disabled);
                // 设置学生信息
                billStudentInfoVO.setStudentId(student.getId());
                billStudentInfoVO.setBillStudentId(eduBillStudent.getId());
                return billStudentInfoVO;
            }).collect(Collectors.toList()));
        });
        return billInfoVO;
    }

    @Override
    public void saveBill(BillSaveDTO billSaveDTO) {
//        log.info("保存缴费单数据: {}", billSaveDTO);
        EduBill eduBill = new EduBill();
        BeanUtils.copyProperties(billSaveDTO, eduBill);
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        // TODO 2021/12/29 此处暂时只有学校, 后续处理其它角色类型
        eduBill.setDeptId(currentUser.getDeptId());

        if (Objects.nonNull(eduBill.getBillStartDate())
                && Objects.nonNull(eduBill.getBillEndDate())
                && eduBill.getBillEndDate().isBefore(eduBill.getBillStartDate())) {
            throw new FebsException("缴费单结束时间应大于开始时间");
        }
        // 开始时间大于当前时间, 删除对应的缴费学生列表数据和缴费项目数据
        if (Objects.nonNull(billSaveDTO.getId())
                && (Objects.isNull(billSaveDTO.getOldBillStartDate())
                || billSaveDTO.getOldBillStartDate().isAfter(LocalDateTime.now()))) {
            // 删除对应的缴费项目选项数据
            List<Long> itemIdList = eduBillItemService.list(
                    new LambdaQueryWrapper<>(new EduBillItem()).eq(EduBillItem::getBillId, billSaveDTO.getId()))
                    .stream().map(EduBillItem::getId).collect(Collectors.toList());
            eduBillItemSubService.remove(
                    new LambdaQueryWrapper<>(new EduBillItemSub()).in(EduBillItemSub::getItemId, itemIdList));
            // 删除对应的缴费项目数据
            eduBillItemService.remove(
                    new LambdaQueryWrapper<>(new EduBillItem()).eq(EduBillItem::getBillId, billSaveDTO.getId()));
            // 删除对应的缴费学生列表数据
            eduBillStudentService.remove(
                    new LambdaQueryWrapper<>(new EduBillStudent()).eq(EduBillStudent::getBillId, billSaveDTO.getId()));
        }
        saveOrUpdate(eduBill);
        boolean flag = Objects.isNull(billSaveDTO.getId()) ||
                (Objects.nonNull(billSaveDTO.getId()) &&
                        (Objects.isNull(billSaveDTO.getOldBillStartDate())
                                || billSaveDTO.getOldBillStartDate().isAfter(LocalDateTime.now())));
        List<EduBillItem> saveItemList = new ArrayList<>();
        if (flag) {
            // 保存对应的缴费项目数据
            billSaveDTO.getItemList().forEach(billItemSaveDTO -> {
                EduBillItem eduBillItem = new EduBillItem();
                BeanUtils.copyProperties(billItemSaveDTO, eduBillItem);
                eduBillItem.setId(null);
                eduBillItem.setBillId(eduBill.getId());
                if (ArrayUtil.isNotEmpty(billItemSaveDTO.getFamilyType())) {
                    eduBillItem.setFamilyType(ArrayUtil.join(billItemSaveDTO.getFamilyType(), ","));
                }

                // 添加子选项
                if (CollUtil.isNotEmpty(billItemSaveDTO.getSubItemList())) {
                    List<EduBillItemSub> subItemList = new ArrayList<>();
                    billItemSaveDTO.getSubItemList().forEach(billSubItemSaveDTO -> {
                        EduBillItemSub eduBillItemSub =
                                EduBillItemSub.builder()
                                        .billId(eduBill.getId())
                                        .subItemName(billSubItemSaveDTO.getSubItemName())
                                        .subItemPrice(billSubItemSaveDTO.getSubItemPrice())
                                        .build();
                        subItemList.add(eduBillItemSub);
                    });
                    eduBillItem.setSubItemList(subItemList);
                }
                saveItemList.add(eduBillItem);
            });

            // 保存对应的缴费学生列表数据
            List<EduBillStudent> saveStudentList = new ArrayList<>();
            billSaveDTO.getAchieveList().forEach(billChooseStudentDTO -> {
                EduBillStudent eduBillStudent = new EduBillStudent();
                BeanUtils.copyProperties(billChooseStudentDTO, eduBillStudent);
                eduBillStudent.setBillId(eduBill.getId());
                saveStudentList.add(eduBillStudent);
            });
            if (CollUtil.isNotEmpty(saveStudentList)) {
                eduBillStudentService.saveBatch(saveStudentList);
            }
        } else {
            // 修改是否必选
            billSaveDTO.getItemList().forEach(billItemSaveDTO -> {
                EduBillItem eduBillItem = new EduBillItem();
                eduBillItem.setId(billItemSaveDTO.getId());
                eduBillItem.setMustPay(billItemSaveDTO.getMustPay());
                saveItemList.add(eduBillItem);
            });
        }
        if (CollUtil.isNotEmpty(saveItemList)) {
            saveItemList.forEach(eduBillItem -> {
                eduBillItemService.saveOrUpdate(eduBillItem);
                if (CollUtil.isNotEmpty(eduBillItem.getSubItemList())) {
                    // 添加子选项
                    eduBillItem.getSubItemList().forEach(itemSub -> itemSub.setItemId(eduBillItem.getId()));
                    eduBillItemSubService.saveOrUpdateBatch(eduBillItem.getSubItemList());
                }
            });
        }
        // TODO 2021/12/30 开始时间定时发送通知给家长
    }

    @Override
    public void updateBillEnableStatus(Long billId, Integer enableStatus) {
        EduBill eduBill = new EduBill();
        eduBill.setId(billId);
        eduBill.setEnableStatus(enableStatus);
        eduBill.setLastEnableDate(LocalDateTime.now());
        saveOrUpdate(eduBill);
    }

    @Override
    public void deleteBill(Long billId) {
        // 判断能否删除
        EduBill bill = getById(billId);
        if (Objects.nonNull(bill)) {
            if (BillStatusEnum.ENABLE_STATUS.getStatus().equals(bill.getEnableStatus())) {
                throw new FebsException("当前账单已启用, 无法删除！");
            }
            if (Objects.isNull(bill.getBillStartDate()) ||
                    Objects.nonNull(bill.getBillStartDate()) && bill.getBillStartDate().isAfter(LocalDateTime.now())) {
                // 删除项目子选项
                eduBillItemSubService.remove(
                        new LambdaQueryWrapper<>(new EduBillItemSub()).eq(EduBillItemSub::getBillId, billId));
                // 删除对应的缴费项目数据
                eduBillItemService.remove(
                        new LambdaQueryWrapper<>(new EduBillItem()).eq(EduBillItem::getBillId, billId));
                // 删除对应的缴费学生列表数据
                eduBillStudentService.remove(
                        new LambdaQueryWrapper<>(new EduBillStudent()).eq(EduBillStudent::getBillId, billId));
                // 删除账单
                removeById(billId);
            } else {
                throw new FebsException("当前账单无法删除");
            }
        }
    }

    @Override
    public List<BillItemInfoVO> listBillPayDetailTableCol(Long billId) {

        // 查询缴费项目信息
        List<EduBillItem> itemList = eduBillItemService.list(
                new LambdaQueryWrapper<>(new EduBillItem()).eq(EduBillItem::getBillId, billId)
                        .orderByAsc(EduBillItem::getId));
        List<BillItemInfoVO> list;
        if (CollUtil.isNotEmpty(itemList)) {
            list = itemList.stream().map(eduBillItem -> {
                BillItemInfoVO billItemInfoVO = new BillItemInfoVO();
                BeanUtils.copyProperties(eduBillItem, billItemInfoVO);
                // 查询子选项数据
                List<EduBillItemSub> subItemList = eduBillItemSubService.list(
                        new LambdaQueryWrapper<>(new EduBillItemSub())
                                .eq(EduBillItemSub::getItemId, eduBillItem.getId()));

                billItemInfoVO.setSubItemList(subItemList.stream().map(subItem -> {
                    BillSubItemInfoVO billSubItemInfoVO = new BillSubItemInfoVO();
                    BeanUtils.copyProperties(subItem, billSubItemInfoVO);
                    return billSubItemInfoVO;
                }).collect(Collectors.toList()));

                return billItemInfoVO;
            }).collect(Collectors.toList());
        } else {
            list = new ArrayList<>();
        }
        return list;
    }

    @Override
    public IPage<BillOrderSelectPageVO> listBillOrderPage(BillOrderSelectPageDTO dto) {

        // 登陆用户信息
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        // TODO 2022/6/29 此处暂时只有学校, 后续处理其它角色类型
        dto.setSchoolId(currentUser.getDeptId());

        Page<BillOrderSelectPageVO> page = Page.of(dto.getPageNum(), dto.getPageSize());
        // 查询账单人员列表
        List<BillOrderSelectPageVO> list = baseMapper.listBillOrderPage(page, dto, new ArrayList<>());
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(vo -> {
                final String[] result = {""};
                // 查询缴费项目信息
                List<EduBillOrderItem> orderItemList = eduBillOrderItemService.list(
                        new LambdaQueryWrapper<>(new EduBillOrderItem())
                                .eq(EduBillOrderItem::getOrderId, vo.getOrderId()));
                // 查询子选项信息
                orderItemList.forEach(item -> {
                    List<EduBillOrderItemSub> itemSubList = eduBillOrderItemSubService.list(
                            new LambdaQueryWrapper<>(new EduBillOrderItemSub())
                                    .eq(EduBillOrderItemSub::getOrderItemId, item.getId()));
                    // 有子选项
                    if (CollUtil.isNotEmpty(itemSubList)) {
                        String collect = itemSubList.stream()
                                .map(EduBillOrderItemSub::getSubItemName)
                                .collect(Collectors.joining(","));
                        result[0] += item.getItemName() + "(" + collect + ")" + StringConstant.COMMA;
                    } else {
                        // 没有子选项
                        result[0] += item.getItemName() + StringConstant.COMMA;
                    }
                });

                if (StringUtils.isNotBlank(result[0])) {
                    vo.setItems(StrUtil.removeSuffix(result[0], StringConstant.COMMA));
                }
            });
        }
        page.setRecords(list);
        return page;
    }

    @Override
    public void refundOrder(String orderCode) {
        h5EduBillService.refundOrder(orderCode);
    }

    @Override
    public List<EduBill> listBill(Integer type) {
        return list(Wrappers.lambdaQuery(new EduBill())
                .eq(EduBill::getDeptId, FebsUtil.getTopDeptId())
                .lt(type == 1, EduBill::getBillStartDate, LocalDateTime.now()));
    }
}
