package org.matrix.remote.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.matrix.local.entity.Project;
import org.matrix.local.entity.User;
import org.matrix.local.entity.UserProject;
import org.matrix.local.mapper.KsProjectMapper;
import org.matrix.local.mapper.KsUserMapper;
import org.matrix.local.mapper.KsUserProjectMapper;
import org.matrix.remote.entity.ZtProject;
import org.matrix.remote.entity.ZtUser;
import org.matrix.remote.entity.ZtUserView;
import org.matrix.remote.mapper.ZtProjectMapper;
import org.matrix.remote.mapper.ZtUserMapper;
import org.matrix.remote.mapper.ZtUserViewMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static java.util.Objects.nonNull;

/**
 * 禅道数据收集工具
 */
@Service
public class DataCollector {

    @Autowired
    private ZtUserMapper ztUserMapper;
    @Autowired
    private ZtUserViewMapper ztUserViewMapper;
    @Autowired
    private ZtProjectMapper ztProjectMapper;
    @Autowired
    private KsUserMapper ksUserMapper;
    @Autowired
    private KsProjectMapper ksProjectMapper;
    @Autowired
    private KsUserProjectMapper ksUserProjectMapper;

    private List<ZtUser> ztUsers = new ArrayList<>();
    private List<ZtUserView> ztUserViews = new ArrayList<>();
    private List<ZtProject> ztProjects = new ArrayList<>();

    /**
     * 执行一次全量同步
     */
    public void execute() {
        //用户数据
        collectUser();
        saveUser();
        //项目数据
        collectProject();
        saveProject();
        //用户项目关系数据
        collectUserView();
        saveUserProject();
    }

    //------------------------------------private-------------------------------------

    /**
     * 从禅道数据库读取用户数据
     */
    private void collectUser() {
        ztUsers.clear();
        ztUsers = ztUserMapper.selectList(Wrappers.lambdaQuery());
    }


    /**
     * 从禅道数据库读取项目数据
     */
    private void collectProject() {
        ztProjects.clear();
        ztProjects = ztProjectMapper.selectList(Wrappers.<ZtProject>lambdaQuery()
                .eq(ZtProject::getDeleted, "0")
                .eq(ZtProject::getProject, 0));
    }

    /**
     * 从禅道数据库读取用户相关项目关系数据
     */
    private void collectUserView() {
        ztUserViews.clear();
        ztUserViews = ztUserViewMapper.selectList(Wrappers.lambdaQuery());
    }

    /**
     * 将用户数据保存到本地
     */
    private void saveUser() {
        ksUserMapper.delete(Wrappers.lambdaQuery());
        ztUsers.stream()
                .map(this::user)
                .forEach(ksUserMapper::insert);
    }

    /**
     * 将项目数据保存到本地
     */
    private void saveProject() {
        ksProjectMapper.delete(Wrappers.lambdaQuery());
        ztProjects.stream()
                .map(this::project)
                .forEach(ksProjectMapper::insert);
    }

    /**
     * 将用户项目关系数据保存到本地
     */
    private void saveUserProject() {
        ksUserProjectMapper.delete(Wrappers.lambdaQuery());
        ztUserViews.stream()
                .flatMap(ztUserView -> userProjects(ztUserView).stream())
                .forEach(ksUserProjectMapper::insert);
    }

    //------------------------private------------------------------------//

    private User user(ZtUser ztUser) {
        return new User(Long.valueOf(ztUser.getId()), ztUser.getRealname(), ztUser.getAccount(), ztUser.getPassword());
    }

    private Project project(ZtProject ztProject) {
        return new Project(Long.valueOf(ztProject.getId()), ztProject.getName());
    }

    private List<UserProject> userProjects(ZtUserView ztUserView) {
        Long userId = ksUserMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getAccount, ztUserView.getAccount())).getId();
        return toList(ztUserView.getProjects()).stream()
                .map(Integer::parseInt)
                .map(id -> ztProjectMapper.selectById(id))
                .filter(ztProject -> Objects.equals("0", ztProject.getDeleted()))
                .map(this::findProjectId)
                .map(projectId -> new UserProject(null, userId, projectId))
                .collect(Collectors.toList());
    }


    private Long findProjectId(ZtProject ztProject) {
        if (nonNull(ztProject.getProject()) && ztProject.getProject() > 0) {
            return Long.valueOf(ztProject.getProject());
        } else {
            return Long.valueOf(ztProject.getId());
        }
    }

    private List<String> toList(String content) {
        List<String> result = Arrays.stream(content.split(",")).collect(Collectors.toList());
        result.remove(0);
        return result;
    }

}
