package org.matrix.remote.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
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.Change;
import org.matrix.remote.entity.ZtProject;
import org.matrix.remote.entity.ZtUser;
import org.matrix.remote.entity.ZtUserView;
import org.matrix.remote.mapper.ChangeMapper;
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.List;
import java.util.Objects;

import static java.util.Objects.nonNull;

/**
 * 禅道数据增量同步工具（基于触发器和专用表）
 */
@Slf4j
@Service
public class DataTriggerCollector {

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

    /**
     * 执行一次增量同步
     */
    public void execute() {
        boolean hasChanges = changeMapper.selectCount(Wrappers.lambdaQuery()) > 0;
        if (hasChanges) {
            List<Change> changes = changeMapper.selectList(Wrappers.lambdaQuery());
            changes.forEach(this::handle);
        }
    }

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

    private void handle(Change change) {
        String table = change.getTable();
        log.info("发现数据变更 数据类型:{} 操作类型:{} 主键:{}", change.getTable(), change.getType(), change.getKey());
        switch (table) {
            case "user":
                handleUser(change);
                return;
            case "project":
                handleProject(change);
                return;
            case "userview":
                handleUserView(change);
                return;
            default:
        }
        changeMapper.delete(Wrappers.lambdaQuery(change));
    }

    private void handleUser(Change change) {
        Integer id = Integer.valueOf(change.getKey());
        ZtUser ztUser = ztUserMapper.selectById(id);
        String type = change.getType();
        switch (type) {
            case "insert":
                if (nonNull(ztUser)) {
                    User user = transHelper.user(ztUser);
                    ksUserMapper.insert(user);
                }
                return;
            case "update":
                if (nonNull(ztUser)) {
                    User user = transHelper.user(ztUser);
                    ksUserMapper.updateById(user);
                }
                return;
            case "delete":
                ksUserMapper.deleteById(id);
                return;
            default:
        }
    }

    private void handleProject(Change change) {
        Integer id = Integer.valueOf(change.getKey());
        ZtProject ztProject = ztProjectMapper.selectById(id);
        String type = change.getType();
        switch (type) {
            case "insert":
                if (nonNull(ztProject)) {
                    Project project = transHelper.project(ztProject);
                    ksProjectMapper.insert(project);
                }
                return;
            case "update":
                if (nonNull(ztProject)) {
                    Project project = transHelper.project(ztProject);
                    ksProjectMapper.updateById(project);
                }
                return;
            case "delete":
                ksProjectMapper.deleteById(id);
                return;
            default:
        }
    }

    private void handleUserView(Change change) {
        String account = change.getKey();
        ZtUserView ztUserView = ztUserViewMapper.selectOne(Wrappers.<ZtUserView>lambdaQuery().eq(ZtUserView::getAccount, account));
        String type = change.getType();
        switch (type) {
            case "insert":
            case "update":
                if (nonNull(ztUserView)) {
                    List<UserProject> userProjects = transHelper.userProjects(ztUserView);
                    userProjects.stream().findAny()
                            .map(UserProject::getUserId)
                            .ifPresent(userId -> ksUserProjectMapper.delete(Wrappers.<UserProject>lambdaQuery().eq(UserProject::getUserId, userId)));
                    userProjects.forEach(ksUserProjectMapper::insert);
                }
                return;
            case "delete":
                if (nonNull(ztUserView)) {
                    Long userId = ksUserMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getAccount, ztUserView.getAccount())).getId();
                    ksUserProjectMapper.delete(Wrappers.<UserProject>lambdaQuery().eq(UserProject::getUserId, userId));
                }
                return;
            default:
        }
    }

}
