package com.yonge.cooleshow.biz.dal.service.impl;

import com.dayaedu.cbs.openfeign.client.MusicFeignClientService;
import com.dayaedu.cbs.openfeign.wrapper.music.CbsSubjectWrapper;
import com.dayaedu.cbs.openfeign.wrapper.musicInstrument.CbsMusicalInstrumentWrapper;
import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
import com.yonge.cooleshow.biz.dal.entity.Instrument;
import com.yonge.cooleshow.biz.dal.entity.Subject;
import com.yonge.cooleshow.biz.dal.queryInfo.SubjectQueryInfo;
import com.yonge.cooleshow.biz.dal.service.InstrumentService;
import com.yonge.cooleshow.biz.dal.service.SubjectService;
import com.yonge.cooleshow.biz.dal.wrapper.InstrumentWrapper;
import com.yonge.cooleshow.biz.dal.wrapper.SubjectWrapper;
import com.yonge.cooleshow.common.enums.CacheNameEnum;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.page.PageInfo;
import com.yonge.toolset.base.util.StringUtil;
import com.yonge.toolset.mybatis.dal.BaseDAO;
import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
import com.yonge.toolset.utils.collection.MapUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SubjectServiceImpl extends BaseServiceImpl<Long, Subject> implements SubjectService {
    private static final Logger log = LoggerFactory.getLogger(MusicSheetServiceImpl.class);

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SubjectDao subjectDao;
    @Resource
    private MusicFeignClientService musicFeignClientService;
    @Resource
    private InstrumentService instrumentService;

    @Override
    public BaseDAO<Long, Subject> getDAO() {
        return subjectDao;
    }

    @Override
    public SubjectDao getDao() {
        return subjectDao;
    }

    @Override
    public List<Subject> findBySubjectByIdList(List<Long> subjectIdList) {
        if (CollectionUtils.isEmpty(subjectIdList)) {
            return new ArrayList<>();
        }
        return subjectDao.findBySubjectIds(subjectIdList);
    }

    @Override
    public List<Subject> findBySubjectByIdList(String subjectIdList) {
        return subjectDao.findBySubjectByIdList(subjectIdList);
    }

    @Override
    public PageInfo<Subject> queryPageTree(SubjectQueryInfo queryInfo) {
        PageInfo<Subject> pageInfo = queryPage(queryInfo);
        for (Subject subject : pageInfo.getRows()) {
             getTree(subject, queryInfo.getDelFlag());
        }
        return pageInfo;
    }

    @Override
    public int deleteById(Long id) {
        List<Subject> subjectList = subjectDao.findByParentId(id);
        if (subjectList != null && subjectList.size() > 0) {
            throw new BizException("该分类下已创建下级，无法删除");
        }
        Boolean flag = subjectDao.useSubject(id);
        if (flag) {
            throw new BizException("该分类有用户使用，无法删除");
        }
        return subjectDao.deleteById(id);
    }

    @Override
    @Transactional
    public void upSetSubject(Subject subject) {
        Subject subjectByCode = subjectDao.queryByCode(subject.getCode());
        if (subjectByCode != null && subjectByCode.getId() != subject.getId()) {
            throw new BizException("声部编码已存在，请修改编码");
        }

        Subject subjectByName = subjectDao.queryByName(subject.getName());
        if (subjectByName != null && subjectByName.getId() != subject.getId()) {
            throw new BizException("名称已存在，请修改名称");
        }
        if (subject.getParentSubjectId() != null && subject.getParentSubjectId() >0) {
            Subject parentSubject = subjectDao.get(subject.getParentSubjectId());
            if (parentSubject == null) {
                throw new BizException("上级声部不存在");
            }
        }

        if (subject.getId() != null) {
            subject.setUpdateTime(new Date());
            subjectDao.update(subject);
            if (subject.getCbsSubjectId() == null) {
                subjectDao.updateCbsSubjectIdNull(subject.getId());
            }
        } else {
            subjectDao.insert(subject);
        }
    }

    @Override
    public List<Subject> subjectSelect(String type, String userExtSubjectIds) {
        Object cacheRes = redissonClient.getBucket(CacheNameEnum.SUBJECT_ITEM.getRedisKey(type)).get();
        if (null != cacheRes) {
            List<Subject> resList = (List<Subject>) cacheRes;
            if (!CollectionUtils.isEmpty(resList)) {
                return resList;
            }
        }

        List<Subject> parents;
        List<Subject> subjects;

        if(StringUtil.isEmpty(type)){
            List<Subject> allList = subjectDao.getAll();

            parents = allList.stream()
                    .filter(o -> (null == o.getParentSubjectId() || o.getParentSubjectId().equals(0L)))
                    .collect(Collectors.toList());

            subjects = allList.stream()
                    .filter(o -> !(null == o.getParentSubjectId() || o.getParentSubjectId().equals(0L)))
                    .collect(Collectors.toList());
        }else{
            subjects = subjectDao.subjectSelect(type);
            
            if(subjects == null){
            	subjects = new ArrayList<Subject>();
            }
            if(StringUtils.isNotBlank(userExtSubjectIds)){
            	List<Long> idList = subjects.stream().map(t -> t.getId()).collect(Collectors.toList());
            	
            	List<Subject> extSubjectList = findBySubjectByIdList(userExtSubjectIds);
            	for(Subject ext : extSubjectList){
            		if(!idList.contains(ext.getId())){
            			subjects.add(ext);
            		}
            	}
            }

            List<Long> parentIds = subjects.stream().map(Subject::getParentSubjectId).collect(Collectors.toList());

            if(CollectionUtils.isEmpty(parentIds)){
                return subjectSelect(null, null);
            }
            parents = findBySubjectByIdList(parentIds);
        }


        for (Subject parent : parents) {
            if (null == parent.getId()) {
                continue;
            }
            for (Subject subject : subjects) {
                if (null == subject.getId() || null == subject.getParentSubjectId()) {
                    continue;
                }
                if (subject.getParentSubjectId().equals(parent.getId())) {
                    List<Subject> children = parent.getSubjects();
                    if (CollectionUtils.isEmpty(children)) {
                        children = new ArrayList<>();
                    }
                    children.add(subject);
                    parent.setSubjects(children);
                }
            }
        }

        redissonClient.getBucket(CacheNameEnum.SUBJECT_ITEM.getRedisKey(type)).set(parents,
                CacheNameEnum.STUDENT_SUBJECT_ITEM.getDuration().toMinutes(),TimeUnit.MINUTES);
        return parents;
    }

    @Override
    public Map<Integer, Subject> getMapByIds(List<String> subjectIds) {

        if(CollectionUtils.isEmpty(subjectIds)){
            return new HashMap<>();
        }

        List<Subject> subjectList = subjectDao.findBySubjectByIdList(subjectIds.stream()
            .filter(StringUtils::isNotBlank).collect(Collectors.joining(",")));
        if(CollectionUtils.isEmpty(subjectList)){
            return new HashMap<>();
        }

        return subjectList.stream().collect(Collectors.toMap(o -> o.getId().intValue(), o -> o));
    }

    @Override
    public Map<Integer, Subject> getAllMap() {
        List<Subject> all = subjectDao.getAll();
        if(CollectionUtils.isEmpty(all)){
            return new HashMap<>();
        }
        return all.stream().collect(Collectors.toMap(o -> o.getId().intValue(), o -> o));
    }

    @Override
    public void add(SubjectWrapper.AddSubject add) {
        List<SubjectWrapper.AddSubjectInstrument> subjects = add.getSubjects();
        if (CollectionUtils.isEmpty(subjects)) {
            throw new BizException("声部不能为空");
        }
        // 声部ID集合
        String cbsSubjectIds = subjects.stream().map(e->e.getCbsSubjectId().toString()).collect(Collectors.joining(","));
        // 查询声部是否存在
        List<Subject> subjectList = subjectDao.getByCbsSubjectIds(cbsSubjectIds);
        // 已存在的cbsId集合
        Map<Long,Long> cbsSubjectMap = subjectList.stream()
                .collect(Collectors.toMap(Subject::getCbsSubjectId, Subject::getId,(o1, o2)->o1));

        // 乐器ID集合
        List<Long> instrumentIds = subjects.stream().filter(o -> org.apache.commons.collections.CollectionUtils.isNotEmpty(o.getInstrumentIds()))
                .flatMap(o -> o.getInstrumentIds().stream()).distinct().collect(Collectors.toList());

        Map<Long, CbsMusicalInstrumentWrapper.MusicalInstrumentQueryDto> instrumentQueryDtoMap = new HashMap<>();

        // 查询乐器信息
        CbsMusicalInstrumentWrapper.MusicalInstrumentQuery musicalInstrumentQuery = new CbsMusicalInstrumentWrapper.MusicalInstrumentQuery();
        musicalInstrumentQuery.setIds(instrumentIds.stream().map(Long::intValue).collect(Collectors.toList()));
        musicalInstrumentQuery.setPage(1);
        musicalInstrumentQuery.setRows(9999);
        try {
            List<CbsMusicalInstrumentWrapper.MusicalInstrumentQueryDto> rows = musicFeignClientService
                    .musicalInstrumentPage(musicalInstrumentQuery).feignData().getRows();
            instrumentQueryDtoMap = rows.stream().collect(Collectors.toMap(o->o.getId().longValue(),o->o,(o1,o2)->o1));
        }catch (Exception e){
            log.error("调用音乐服务查询乐器失败", e);
            throw new com.microsvc.toolkit.common.webportal.exception.BizException("内容平台服务异常");
        }

        List<Instrument> saveInstrumentList = new ArrayList<>();
        // 保存声部
        for (SubjectWrapper.AddSubjectInstrument addSubject : subjects) {
            Long subjectId;
            if (!cbsSubjectMap.containsKey(addSubject.getCbsSubjectId())) {
                Subject subject = new Subject();
                subject.setCbsSubjectId(addSubject.getCbsSubjectId());
                subject.setEnableFlag(false);
                subject.setParentSubjectId(addSubject.getParentSubjectId());
                this.insert(subject);
                subjectId= subject.getId();
            } else {
                subjectId = cbsSubjectMap.get(addSubject.getCbsSubjectId());
            }
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(addSubject.getInstrumentIds())) {
                for (Long instrumentId : addSubject.getInstrumentIds()) {
                    Instrument instrument = new Instrument();
                    instrument.setId(instrumentId);
                    instrument.setSubjectId(subjectId);
                    instrument.setEnableFlag(false);
                    instrument.setOperator(add.getOperator());
                    CbsMusicalInstrumentWrapper.MusicalInstrumentQueryDto musicalInstrumentQueryDto = instrumentQueryDtoMap.get(instrumentId);
                    if (musicalInstrumentQueryDto != null) {
                        instrument.setOrientation(musicalInstrumentQueryDto.getOrientation());
                    } else {
                        instrument.setOrientation(false);
                    }
                    saveInstrumentList.add(instrument);
                }
            }

        }
        instrumentService.saveOrUpdateBatch(saveInstrumentList);
    }

    @Override
    public Boolean enable(Subject subject) {
        // 停用声部，同时停用声部下的乐器
        subjectDao.update(subject);
        if (Boolean.FALSE.equals(subject.getEnableFlag())) {
            instrumentService.lambdaUpdate()
                    .eq(Instrument::getSubjectId, subject.getId())
                    .eq(Instrument::getEnableFlag, true)
                    .set(Instrument::getEnableFlag, false)
                    .update();
        }
        return true;
    }

    @Override
    public PageInfo<SubjectWrapper.Subject> selectPage(SubjectWrapper.SubjectQuery query) {
        PageInfo<SubjectWrapper.Subject> pageInfo = new PageInfo<>(query.getPage(), query.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, query);

        List<SubjectWrapper.Subject> dataList = null;
        int count = subjectDao.findCount(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = subjectDao.findPage(params);
            if(query.getParentSubjectId() == null || query.getParentSubjectId() > 0){
                // 转map
                Map<Long, SubjectWrapper.Subject> subjectMap = dataList.stream().collect(Collectors.toMap(SubjectWrapper.Subject::getCbsSubjectId, Function.identity(),(o1, o2)->o1));
                // cbs声部ID集合
                List<Long> cbsSubjectIds = dataList.stream().map(SubjectWrapper.Subject::getCbsSubjectId).collect(Collectors.toList());
                dataList = new ArrayList<>();
                CbsSubjectWrapper.SubjectQuery subjectQuery = new CbsSubjectWrapper.SubjectQuery();
                subjectQuery.setIds(cbsSubjectIds);
                subjectQuery.setPage(1);
                subjectQuery.setRows(query.getRows());
                try {
                    com.microsvc.toolkit.common.response.paging.PageInfo<CbsSubjectWrapper.Subject> subjectPageInfo = musicFeignClientService.subjectPage(subjectQuery).feignData();
                    List<CbsSubjectWrapper.Subject> rows = subjectPageInfo.getRows();
                    if (org.apache.commons.collections.CollectionUtils.isNotEmpty(rows)) {
                        for (CbsSubjectWrapper.Subject row : rows) {
                            SubjectWrapper.Subject subject = subjectMap.get(row.getId());
                            if (subject == null) {
                                log.warn("未查询到声部信息，id:{}", row.getId());
                                continue;
                            }
                            subject.setCbsSubjectName(row.getName());
//                            subject.setName(row.getName());
//                            subject.setCode(row.getCode());
                            dataList.add(subject);
                        }
                    }
                } catch (Exception e) {
                    log.error("调用音乐服务查询曲目详情失败", e);
                }
                // 设置声部下的乐器信息
                List<Integer> subjectIds = dataList.stream().map(SubjectWrapper.Subject::getId).distinct().collect(Collectors.toList());
                Map<Integer, List<InstrumentWrapper.Instrument>> groupBySubjectId = instrumentService.getGroupBySubjectId(subjectIds, query.getEnableFlag());
                Map<Long, Subject> map = this.findBySubjectByIdList(dataList.stream().map(SubjectWrapper.Subject::getParentSubjectId).collect(Collectors.toList())).stream()
                        .collect(Collectors.toMap(Subject::getId, t -> t));
                dataList.forEach(e -> {
                    if(e.getParentSubjectId() != null && e.getParentSubjectId() > 0) {
                        e.setParentSubjectName(map.get(e.getParentSubjectId()).getName());
                    }
                    List<InstrumentWrapper.Instrument> instruments = groupBySubjectId.get(e.getId());
                    if (org.apache.commons.collections.CollectionUtils.isNotEmpty(instruments)) {
                        e.setInstruments(instruments);
                    }
                });
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public List<SubjectWrapper.Subject> list(SubjectWrapper.SubjectQuery query) {
        query.setPage(1);
        query.setRows(9999);
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, query);

        PageInfo<SubjectWrapper.Subject> subjectIPage = this.selectPage(query);
        List<SubjectWrapper.Subject> records = subjectIPage.getRows();
        if (CollectionUtils.isEmpty(records)) {
            return records;
        }
        String instrumentIds = query.getInstrumentIds();
        List<Long> instrumentIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(instrumentIds)) {
            List<Long> collect = Arrays.stream(instrumentIds.split(",")).map(Long::valueOf).distinct().collect(Collectors.toList());
            instrumentIdList.addAll(collect);
        }
        if (!instrumentIdList.isEmpty()) {
            records.forEach(record -> {
                List<InstrumentWrapper.Instrument> instruments = record.getInstruments();
                instruments.removeIf(next -> !instrumentIdList.contains(next.getId()));
            });
        }
        return records;
    }

    @Override
    public void convertSubject(List<Subject> subjectSelect) {
//        convert(subjectSelect);
    }

    private void convert(List<Subject> subjects){
        /*if(CollectionUtils.isNotEmpty(subjects)){
            // cbs声部ID集合
            List<Long> cbsSubjectIds = subjects.stream().map(Subject::getCbsSubjectId).collect(Collectors.toList());
            CbsSubjectWrapper.SubjectQuery subjectQuery = new CbsSubjectWrapper.SubjectQuery();
            subjectQuery.setIds(cbsSubjectIds);
            subjectQuery.setPage(1);
            subjectQuery.setRows(cbsSubjectIds.size());
            try {
                com.microsvc.toolkit.common.response.paging.PageInfo<CbsSubjectWrapper.Subject> subjectPageInfo = musicFeignClientService.subjectPage(subjectQuery).feignData();
                List<CbsSubjectWrapper.Subject> rows = subjectPageInfo.getRows();
                if (CollectionUtils.isNotEmpty(rows)) {
                    Map<Long,CbsSubjectWrapper.Subject> cbsMap = rows.stream().collect(Collectors.toMap(CbsSubjectWrapper.Subject::getId, Function.identity(),(o1, o2)->o1));
                    for (Subject row : subjects) {
                        CbsSubjectWrapper.Subject subject = cbsMap.get(row.getCbsSubjectId());
                        if (subject == null) {
                            log.warn("未查询到声部信息，id:{}", row.getId());
                            continue;
                        }
                        row.setName(subject.getName());
                        row.setCode(subject.getCode());
                    }
                }
            } catch (Exception e) {
                log.error("调用音乐服务查询曲目详情失败", e);
            }
        }*/
    }

    @Override
    public void convertSubSubject(List<Subject> subjectSelect) {
        if(CollectionUtils.isNotEmpty(subjectSelect)){
            for (Subject entity : subjectSelect) {
                convert(entity.getSubjects());
            }
        }
    }


    /***
     * 查询声部树
     * @param: sub
     * @param: yesOrNoEnum
     * @updateTime 2022/4/6 11:33
     * @return: com.yonge.cooleshow.biz.dal.entity.Subject
     */
    private Subject getTree(Subject sub, Boolean delFlag) {
        //得到根节点对象
        //获取子节点list
        List<Subject> subjects = subjectDao.findByParentId(sub.getId());
        //如果存在子节点
        if (subjects != null && subjects.size() > 0) {
            //将子节点list放入父节点对象
            sub.setSubjects(subjects);
            //遍历子节点....
            for (Subject subject : subjects) {
                getTree(subject, delFlag);
            }
        }
        return sub;
    }
}
