package com.infoepoch.pms.dispatchassistant.domain.basic.todo;

import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.domain.oa.OaService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 待办Service
 */
@Service
public class TodoService {
    private static final Logger logger = LoggerFactory.getLogger(TodoService.class);

    @Value("${spring.application.name}")
    private String appName;

    @Autowired
    private OaService oaService;

    //通过构造函数注入
    @Autowired
    private ITodoRepository todoRepository;


    /**
     * @Description: 创建流程代办
     * @Param: [documentType, domainId, processId, activityId, stage, drafter, drafterName, title, url, sender, senderName, receiver, receiverName]
     * @Author: zhangyd
     */
    public Todo sendPeTodo(String documentType, String domainId, String processId, String activityId, String stage, String drafter, String drafterName,
                           String title, String url, String sender, String senderName, String receiver, String receiverName, String moaUrl) {
        Todo todo = new Todo(documentType, domainId, processId, activityId, stage, drafter, drafterName, TodoType.TODO, TodoLevel.NORMAL,
                title, url, new Date(), sender, senderName, receiver, receiverName, null, null, moaUrl);
        //持久化代办
        repositoryTodo(todo);
        try {
            // 同步OA待办
            oaService.syncTodo(todo);
        } catch (Exception e) {
            logger.info("同步OA待办失败");
            e.printStackTrace();
        }
        return todo;
    }

    //endregion

    /**
     * @Description: 取所有代办单据类型
     * @Param: []
     * @Author: zhangyd
     */
    public List<String> getDocumentTypes() {
        return todoRepository.selectDocumentTypes();
    }

    /**
     * @Description: 发送衔接代办
     * @Param: [todoId, documentType, domainId, stage, drafter, drafterName, type, level, title, url, sender, senderName, receiver, receiverName, additionalData]
     * @Author: zhangyd
     */
    public Todo sendNoticeTodo(String todoId, String documentType, String domainId, String stage, String drafter, String drafterName, TodoType type, TodoLevel level,
                               String title, String url, String sender, String senderName, String receiver, String receiverName, String additionalData, String urlMoa) {
        if (type == null)
            type = TodoType.TODO;
        if (level == null)
            level = TodoLevel.NORMAL;
        Todo todo = new Todo(todoId, documentType, domainId, null, null, stage, drafter, drafterName, type, level,
                title, url, new Date(), sender, senderName, receiver, receiverName, null, additionalData, null, urlMoa);
        repositoryTodo(todo);
        return todo;
    }

    /**
     * @Description: 处理代办
     * @Param: [criteria, redirectUrl]
     * @Author: zhangyd
     */
    public void actionTodo(TodoCriteria criteria, String redirectUrl, boolean syncFlag) {
        criteria.setAction(false);
        //校验代办必传项
        TodoCriteria.validationActionTodoCriteria(criteria);
        List<Todo> todos = todoRepository.selectByCriteria(criteria);
        for (Todo todo : todos) {
            if (StringUtils.isNotBlank(redirectUrl))
                todo.resetUrl(redirectUrl);
            todo.action();
            todoRepository.updateAction(todo);
        }
        if (syncFlag) {
            try {
                oaService.syncTodoList(todos);
            } catch (Exception e) {
                logger.info("同步OA待办失败");
                e.printStackTrace();
            }
        }
//        todoRepository.batchUpdate(todos);
    }

    /**
     * 处理待办
     *
     * @param todo
     */
    public void actionTodo(Todo todo) {
        actionTodo(todo, null, true);
    }

    /**
     * 处理待办
     *
     * @param todo
     * @param syncFlag
     */
    public void actionTodo(Todo todo, String redirectUrl, boolean syncFlag) {
        if (StringUtils.isBlank(todo.getId())) {
            throw new RuntimeException("待办ID不能为空");
        }
        if (StringUtils.isNotBlank(redirectUrl))
            todo.resetUrl(redirectUrl);
        todo.action();
        todoRepository.updateAction(todo);
        if (syncFlag) {
            try {
                oaService.syncTodoList(Collections.singletonList(todo));
            } catch (Exception e) {
                logger.info("同步OA待办失败");
                e.printStackTrace();
            }
        }
    }

    /**
     * @Description: 持久化代办
     * @Param: [todo]
     * @Author: zhangyd
     */
    private void repositoryTodo(Todo todo) {
        todoRepository.insert(todo);
    }

    /**
     * 根据条件查询待办
     *
     * @param criteria
     * @return
     */
    public List<Todo> queryByCriteria(TodoCriteria criteria) {
        return todoRepository.selectByCriteria(criteria);
    }


    /**
     * 发送待办列表，默认过滤掉重复待办
     *
     * @param todoList
     */
    private void sendTodoList(List<Todo> todoList) {
        sendTodoList(todoList, true);
    }

    /**
     * 发送待办列表，可选是否过滤掉重复待办
     *
     * @param todoList
     * @param filterFlag
     */
    private void sendTodoList(List<Todo> todoList, boolean filterFlag) {
        // 校验待办列表
        verifyTodoList(todoList);
        if (filterFlag)
            filterRepeatTodo(todoList); // 过滤重复待办
        if (CollectionUtils.isNotEmpty(todoList)) {
            for (Todo todo : todoList) {
                TodoCriteria criteria = new TodoCriteria();
                // 限定待办类型
                criteria.setDocumentType(todo.getDocumentType());
                // 限定领域ID
                criteria.setDomainId(todo.getDomainId());
                // 限定接收人
                criteria.setReceiver(todo.getReceiver());
                // 限定未处理
                criteria.setAction(false);
                List<Todo> list = queryByCriteria(criteria);
                // 查询出的待办列表为空则发送新的待办，否则不发送待办
                if (CollectionUtils.isEmpty(list)) {
                    repositoryTodo(todo);
                }
            }
        }
    }

    @Async
    public void sendTodoListSync(List<Todo> todoList) {
        sendTodoListSync(todoList, true);
    }

    @Async
    public void sendTodoListSync(List<Todo> todoList, boolean filterFlag) {
        // 校验待办列表
        verifyTodoList(todoList);
        if (filterFlag)
            filterRepeatTodo(todoList); // 过滤重复待办
        if (CollectionUtils.isNotEmpty(todoList)) {
            List<Todo> oaTodoList = new ArrayList<>();
            for (Todo todo : todoList) {
                TodoCriteria criteria = new TodoCriteria();
                // 限定待办类型
                criteria.setDocumentType(todo.getDocumentType());
                // 限定领域ID
                criteria.setDomainId(todo.getDomainId());
                // 限定接收人
                criteria.setReceiver(todo.getReceiver());
                // 限定未处理
                criteria.setActionFlag(false);
                List<Todo> list = queryByCriteria(criteria);
                // 查询出的待办列表为空则发送新的待办，否则不发送待办
                if (CollectionUtils.isEmpty(list)) {
                    todoRepository.insert(todo);
                    oaTodoList.add(todo);
                }
            }
            if (oaTodoList.size() > 0) {
                // 同步待办到OA
                try {
                    oaService.syncTodoList(oaTodoList);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 校验待办列表
     *
     * @param todoList
     */
    private void verifyTodoList(List<Todo> todoList) {
        if (CollectionUtils.isNotEmpty(todoList)) {
            for (Todo todo : todoList) {
                todo.verify();
            }
        }
    }

    /**
     * 过滤重复待办
     *
     * @param todoList
     */
    private void filterRepeatTodo(List<Todo> todoList) {
        if (CollectionUtils.isNotEmpty(todoList)) {
            Set<String> todoKeySet = new HashSet<>();
            Iterator<Todo> iterator = todoList.iterator();
            while (iterator.hasNext()) {
                Todo todo = iterator.next();
                String todoKey = todo.getDocumentType() + ":" + todo.getDomainId() + ":" + todo.getReceiver();
                if (todoKeySet.contains(todoKey)) {
                    iterator.remove();
                } else {
                    todoKeySet.add(todoKey);
                }
            }
        }
    }

    /**
     * 分页获取待办
     *
     * @param criteria
     * @return
     */
    public Map<String, Object> queryList(TodoCriteria criteria) {
        try {
            criteria.removeMapNullOrEmpty();
            if (criteria.byPage()) {
                List<Todo> list = todoRepository.selectByPage(criteria.getPageIndex(), criteria.getPageSize(), criteria);
                fillListData(list);
                int totalCount = todoRepository.selectCount(criteria);
                Map<String, Object> map = new HashMap<>();
                map.put("totalCount", totalCount);
                map.put("dataList", list);
                return map;
            } else {
                List<Todo> list = todoRepository.selectByCriteria(criteria);
                fillListData(list);
                Map<String, Object> map = new HashMap<>();
                map.put("dataList", list);
                return map;
            }
        } catch (Exception e) {
            throw new ValidationException("根据条件查询  列表 数据 失败。");
        }
    }

    /**
     * @param todoList
     */
    private void fillListData(List<Todo> todoList) {
        if (CollectionUtils.isEmpty(todoList))
            return;
        String prefix = "/" + appName;
        for (Todo todo : todoList) {
            if (!todo.getUrl().startsWith(prefix)) {
                todo.resetUrl(prefix + todo.getUrl());
            }
        }
    }

    //待阅转已阅
    public void read(String messageId) {
        todoRepository.read(messageId);
    }
}
