package cn.cslg.pas.service.impl;

import cn.cslg.pas.common.JsonPage;
import cn.cslg.pas.common.model.PersonnelVO;
import cn.cslg.pas.common.model.dto.*;
import cn.cslg.pas.common.model.vo.ApplicationScenarioEventNumberVO;
import cn.cslg.pas.common.model.vo.EventListItemVO;
import cn.cslg.pas.common.model.vo.InvestigationTypeProjectNumberVO;
import cn.cslg.pas.common.utils.CacheUtils;
import cn.cslg.pas.common.utils.SecurityUtils.LoginUtils;
import cn.cslg.pas.common.utils.ThrowException;
import cn.cslg.pas.domain.ApplicationScenario;
import cn.cslg.pas.domain.Event;
import cn.cslg.pas.domain.Project;
import cn.cslg.pas.domain.Type;
import cn.cslg.pas.mapper.EventMapper;
import cn.cslg.pas.mapper.asso.AssoEventProjectMapper;
import cn.cslg.pas.service.IAssoEventProjectService;
import cn.cslg.pas.service.IEventService;
import cn.cslg.pas.service.ProjectService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 事件的Service层接口实现类
 *
 * @Author chenyu
 * @Date 2023/4/2
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class EventServiceImpl extends ServiceImpl<EventMapper, Event> implements IEventService {
    private final ProjectService projectService;
    private final EventMapper eventMapper;
    private final AssoEventProjectMapper assoEventProjectMapper;
    private final IAssoEventProjectService assoEventProjectService;
    private final CacheUtils cacheUtils;
    private final LoginUtils loginUtils;

    /**
     * 新增专题库时批量新增事件中的新事件
     *
     * @param eventAddNewDTOs 新增事件的DTO类对象集合
     * @return 返回事件eventIds
     */
    @Override
    public List<Integer> addNew(List<EventAddNewDTO> eventAddNewDTOs) {
        log.info("开始处理【新增专题库时批量新增新事件（无事件id）】的业务，参数为：{}", eventAddNewDTOs);

        //获取当前登陆人信息取出登陆人id、登陆人名称、租户id
        PersonnelVO personnelVO = cacheUtils.getLoginUser(loginUtils.getId());
        Integer tenantId = personnelVO.getTenantId();
        Integer createPersonId = personnelVO.getId();
        String createPersonName = personnelVO.getName();

        //取出DTOs中的事件名称questionNames，根据事件名称questionNames和租户id查询出重名的已有事件
        List<String> questionNames = eventAddNewDTOs.stream().map(EventAddNewDTO::getQuestionName).collect(Collectors.toList());
        LambdaQueryWrapper<Event> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Event::getQuestionName, questionNames).in(Event::getTenantId, tenantId);
        List<Event> existNamesEvents = this.list(wrapper);
        if (existNamesEvents != null && existNamesEvents.size() > 0) {
            ThrowException.throwXiaoShiException("新增失败，本租户下事件名称【" + existNamesEvents.get(0).getQuestionName() + "已存在，请尝试更换名称】");
        }

        //新增事件
        ArrayList<Event> events = new ArrayList<>();
        for (EventAddNewDTO eventAddNewDTO : eventAddNewDTOs) {
            String questionName = eventAddNewDTO.getQuestionName();
            if (questionName == null || questionName.equals("")) {
                ThrowException.throwXiaoShiException("新增失败，事件名称不能为空");
            }
            Event event = new Event();
            BeanUtils.copyProperties(eventAddNewDTO, event);
            event
                    .setTenantId(tenantId)
                    .setCreatePersonId(createPersonId)
                    .setCreatePersonName(createPersonName);
            List<Integer> applicationScenarios = eventAddNewDTO.getApplicationScenarios();
            //若有应用场景，则将应用场景集合转换成以逗号拼接的字符串，并赋值给实体类对应参数
            if (applicationScenarios != null && applicationScenarios.size() > 0) {
                //StringBuilder builder = new StringBuilder();
                //for (Integer applicationScenario : applicationScenarios) {
                //    builder.append(applicationScenario).append(",");
                //}
                //String applicationScenario = builder.substring(0, builder.lastIndexOf(","));
                String applicationScenario = applicationScenarios.stream().map(String::valueOf).collect(Collectors.joining(","));
                event.setApplicationScenario(applicationScenario);
            }
            events.add(event);
        }
        //数据入事件表
        this.saveBatch(events);

        ArrayList<Integer> eventIds = new ArrayList<>();
        for (Event event : events) {
            eventIds.add(event.getId());
        }

        log.info("新增事件完成");
        return eventIds;
    }

    /**
     * 新增事件
     *
     * @param projectEventAddNewDTO 专题库新增事件的DTO类对象集合
     */
    @Override
    public void addNewEvent(ProjectEventAddNewDTO projectEventAddNewDTO) {
        log.info("开始处理【新增事件】的业务，参数为：{}", projectEventAddNewDTO);

        //新增事件
        List<EventAddNewDTO> eventAddNewDTOs = projectEventAddNewDTO.getEventAddNewDTOs();
        Integer projectId = projectEventAddNewDTO.getProjectId();
        List<Integer> eventIds = new ArrayList<>();
        //过滤去除已有事件↓(根据是否有id来过滤，有id则为已有事件无需新增，只做关联)
        List<EventAddNewDTO> oldEventAddNewDTOs = eventAddNewDTOs.stream().filter(item -> item.getId() != null).collect(Collectors.toList());
        //遍历已有事件，将事件id添加进事件ids集合
        for (EventAddNewDTO oldEventAddNewDTO : oldEventAddNewDTOs) {
            eventIds.add(oldEventAddNewDTO.getId());
        }

        //过滤后为新事件↓，新事件需要先新增事件，拿到事件ids后再和专题库做关联
        eventAddNewDTOs.removeAll(oldEventAddNewDTOs);
        if (eventAddNewDTOs.size() > 0) {
            List<Integer> newEventIds = this.addNew(eventAddNewDTOs);
            eventIds.addAll(newEventIds);
        }
        //新增事件和专题库关联
        assoEventProjectService.addNew(eventIds, projectId);

    }

    /**
     * 分页查询事件
     *
     * @param eventQueryPageDTO 事件的分页查询DTO类对象
     */
    @Override
    public JsonPage query(EventQueryPageDTO eventQueryPageDTO) {
        log.info("开始处理【分页查询事件】的业务，参数为：{}", eventQueryPageDTO);

        PersonnelVO personnelVO = cacheUtils.getLoginUser(loginUtils.getId());
        eventQueryPageDTO.setTenantId(personnelVO.getTenantId());

        Integer current = eventQueryPageDTO.getCurrent();
        Integer size = eventQueryPageDTO.getSize();
        String orderBy = eventQueryPageDTO.getOrderBy();
        //将前端传来的需要排序的字段做映射转换(如：xxxAxxBxx -> xxx_axx_bxx)
        if (orderBy != null && !orderBy.equals("")) {
            String regex = "[A-Z]+";
            Matcher matcher = Pattern.compile(regex).matcher(orderBy);
            while (matcher.find()) {
                orderBy = orderBy.replaceFirst(matcher.group(), "_" + matcher.group().toLowerCase());
            }
            eventQueryPageDTO.setOrderBy(orderBy);
        }

        if (current != null && size != null) {
            PageHelper.startPage(current, size);
        }

        //开始查询事件
        List<EventListItemVO> queryResults = eventMapper.queryList(eventQueryPageDTO);
        //将以逗号拼接的字符串应用场景applicationScenario转化为应用场景value集合
        for (EventListItemVO queryResult : queryResults) {
            String applicationScenario = queryResult.getApplicationScenario();
            if (applicationScenario != null && !applicationScenario.equals("")) {
                String[] applicationScenarioArr = applicationScenario.split(",");
                ArrayList<Integer> applicationScenarioValues = new ArrayList<>();
                for (String n : applicationScenarioArr) {
                    applicationScenarioValues.add(Integer.parseInt(n));
                }
                queryResult.setApplicationScenarios(applicationScenarioValues);
            }
        }
        return JsonPage.restPage(new PageInfo<>(queryResults));
    }

    /**
     * 查询9大应用场景分别对应的事件数量
     */
    @Override
    public List<ApplicationScenarioEventNumberVO> queryApplicationScenarioEventNumber() {
        log.info("开始处理【查询9大应用场景分别对应的事件数量】的业务");

        PersonnelVO personnelVO = cacheUtils.getLoginUser(loginUtils.getId());
        Integer tenantId = personnelVO.getTenantId();

        //查询所有应用场景(目前为9个应用场景)
        List<ApplicationScenario> applicationScenarios = eventMapper.queryApplicationScenarios();

        //查询所有事件(分为两类：1.有应用场景的事件；2.没有应用场景的事件(该部分事件使用它们所属的专题库的应用场景))
        List<EventListItemVO> eventsDirectApplicationScenario = eventMapper.queryEventsDirectApplicationScenario(tenantId);
        List<EventListItemVO> eventsInDirectApplicationScenario = eventMapper.queryEventsInDirectApplicationScenario(tenantId);
        //装载上述两类事件中的应用场景
        ArrayList<String> applicationScenarioStrs = new ArrayList<>();
        if (eventsDirectApplicationScenario != null) {
            for (EventListItemVO n : eventsDirectApplicationScenario) {
                applicationScenarioStrs.add(n.getApplicationScenario());
            }
        }
        if (eventsInDirectApplicationScenario != null) {
            for (EventListItemVO n : eventsInDirectApplicationScenario) {
                applicationScenarioStrs.add(n.getApplicationScenario());
            }
        }

        //开始装载9大应用场景（应用场景value、应用场景名称、事件数量）↓
        ArrayList<ApplicationScenarioEventNumberVO> results = new ArrayList<>();
        //遍历所有9大应用场景
        for (ApplicationScenario applicationScenario : applicationScenarios) {
            Integer applicationScenarioValue = applicationScenario.getApplicationScenarioValue();
            String applicationScenarioName = applicationScenario.getApplicationScenarioName();
            //定义当前应用场景对应的事件数量为0
            int eventNumber = 0;
            if (applicationScenarioStrs.size() > 0) {
                //遍历所有事件的应用场景
                for (String n : applicationScenarioStrs) {
                    ArrayList<String> applicationScenarioValues = new ArrayList<>(Arrays.asList(n.split(",")));
                    //若当前事件的应用场景集合包含当前正在遍历的应用场景，则当前正在遍历的应用场景对应事件数量 +1
                    if (applicationScenarioValues.contains(applicationScenarioValue + "")) {
                        eventNumber++;
                    }
                }
            }
            ApplicationScenarioEventNumberVO applicationScenarioEventNumberVO = new ApplicationScenarioEventNumberVO()
                    .setApplicationScenarioValue(applicationScenarioValue)
                    .setApplicationScenarioName(applicationScenarioName)
                    .setEventNumber(eventNumber);
            results.add(applicationScenarioEventNumberVO);
        }

        return results;
    }

    /**
     * 根据应用场景value和事件名称分页查询事件清单
     *
     * @param eventQueryPageDTO 查询参数
     */
    @Override
    public JsonPage queryEvents(EventQueryPageDTO eventQueryPageDTO) {
        log.info("开始处理【根据应用场景value和事件名称分页查询事件清单】的业务，参数为：{}", eventQueryPageDTO);

        PersonnelVO personnelVO = cacheUtils.getLoginUser(loginUtils.getId());
        eventQueryPageDTO.setTenantId(personnelVO.getTenantId());
        Integer current = eventQueryPageDTO.getCurrent();
        Integer size = eventQueryPageDTO.getSize();

        if (current != null && size != null) {
            PageHelper.startPage(current, size);
        }

        //根据应用场景value和事件名称分页查询事件清单
        List<EventListItemVO> events = eventMapper.queryEvents(eventQueryPageDTO);
        return JsonPage.restPage(new PageInfo<>(events));
    }

    /**
     * 根据应用场景和事件id查询调查类型对应的专题库数量
     *
     * @param queryInvestigationTypeProjectNumberDTO 查询参数
     * @return 返回查询到的数据
     */
    @Override
    public List<InvestigationTypeProjectNumberVO> queryInvestigationTypeProjectNumber(QueryInvestigationTypeProjectNumberDTO queryInvestigationTypeProjectNumberDTO) {
        log.info("开始处理【根据应用场景和事件id查询调查类型对应的专题库数量】的业务，参数为：{}", queryInvestigationTypeProjectNumberDTO);

        Integer applicationScenario = queryInvestigationTypeProjectNumberDTO.getApplicationScenario();
        Integer eventId = queryInvestigationTypeProjectNumberDTO.getEventId();
        //1.根据应用场景查询出所有调查类型
        List<Type> types = eventMapper.queryTypeid(applicationScenario);
        //2.根据应用场景和事件id查询出所有专题库
        List<Project> projects = eventMapper.queryProjects(applicationScenario, eventId);

        //3.遍历调查类型，在每一个调查类型中遍历专题库，装载调查类型对应的专题库数量
        ArrayList<InvestigationTypeProjectNumberVO> results = new ArrayList<>();
        for (Type type : types) {
            InvestigationTypeProjectNumberVO result = new InvestigationTypeProjectNumberVO();
            result.setInvestigationType(type.getTypeId());
            result.setInvestigationTypeName(type.getTypeName());
            int projectNumber = 0;
            if (projects != null && projects.size() > 0) {
                for (Project project : projects) {
                    if (project.getType() != null) {
                        String[] typeArr = project.getType().split(",");
                        if (new ArrayList<>(Arrays.asList(typeArr)).contains(type.getTypeId() + "")) {
                            projectNumber++;
                        }
                    }
                }
            }
            result.setProjectNumber(projectNumber);
            results.add(result);
        }

        return results;

    }


    /**
     * 修改事件
     *
     * @param eventUpdateDTO 修改事件的DTO类对象
     */
    @Override
    public void update(EventUpdateDTO eventUpdateDTO) {
        log.info("开始处理【修改事件】的业务，参数为：{}", eventUpdateDTO);

        //检查尝试修改的数据是否存在
        Event queryResult = eventMapper.selectById(eventUpdateDTO.getId());
        if (queryResult == null) {
            ThrowException.throwXiaoShiException("修改失败，访问的数据不存在，请尝试刷新页面");
        }

        //若修改了名称，则检查名称是否被占用(同一租户下专题库不能有同名事件名称)
        String newQuestionName = eventUpdateDTO.getQuestionName();
        String oldQuestionName = queryResult.getQuestionName();
        Project project = projectService.getById(eventUpdateDTO.getProjectId());
        Integer tenantId = project.getTenantId();
        if (!newQuestionName.equals(oldQuestionName)) {
            log.info("检查事件名称是否被占用(同一租户下专题库不能有同名事件)");
            int count = eventMapper.countByNameAndTenantId(newQuestionName, tenantId);
            if (count > 0) {
                ThrowException.throwXiaoShiException("修改失败，当前租户下事件名称【" + newQuestionName + "】已存在，请尝试更换名称");
            }
        }

        //修改事件
        Event event = new Event();
        BeanUtils.copyProperties(eventUpdateDTO, event);
        event.setTenantId(tenantId);
        List<Integer> applicationScenarios = eventUpdateDTO.getApplicationScenarios();
        if (applicationScenarios != null && applicationScenarios.size() > 0) {
            String applicationScenario = applicationScenarios.stream().map(String::valueOf).collect(Collectors.joining(","));
            event.setApplicationScenario(applicationScenario);
        }
        int rows = eventMapper.updateById(event);
        if (rows != 1) {
            ThrowException.throwXiaoShiException("修改失败，服务器忙请稍后再次尝试");
        }

        log.info("修改完成");

    }

    /**
     * 根据专题库id删除关联的事件
     *
     * @param eventId   事件id
     * @param projectId 专题库id
     */
    @Override
    public void delete(Integer eventId, Integer projectId) {
        log.info("开始处理【删除事件】的业务，参数为：{}, {}", eventId, projectId);

        //检查尝试删除的数据是否存在
        Event queryResult = eventMapper.selectById(eventId);
        if (queryResult == null) {
            ThrowException.throwXiaoShiException("删除失败，访问的数据不存在，请尝试刷新页面");
        }

        //删除事件和专题库关联表数据
        ArrayList<Integer> eventIds = new ArrayList<>();
        eventIds.add(eventId);
        assoEventProjectMapper.deleteByEventIdsAndProjectId(eventIds, projectId);

        //删除事件表数据
//        int rows = eventMapper.deleteById(eventId);
//        if (rows != 1) {
//            ThrowException.throwXiaoShiException("删除失败，服务器忙请稍后再次尝试");
//        }

        log.info("删除完成");

    }


}
