package cn.axzo.msg.center.message.service.todo.manage;

import cn.axzo.msg.center.dal.TodoBusinessDao;
import cn.axzo.msg.center.dal.TodoBusinesses;
import cn.axzo.msg.center.dal.TodoLogDao;
import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.domain.entity.TodoBusiness;
import cn.axzo.msg.center.domain.entity.TodoLog;
import cn.axzo.msg.center.service.enums.BizCategoryEnum;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.TodoLogType;
import cn.axzo.msg.center.service.enums.TodoType;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author yanglin
 */
@Component
@RequiredArgsConstructor
class TodoLogger {

    private final TodoLogDao todoLogDao;
    private final TodoBusinessDao todoBusinessDao;

    void logBusinessUpdated(TodoRequestContext ctx, TodoBusiness business) {
        TodoLog log = createBusinessLog(ctx, business);
        log.setContext(ctx.getName());
        log.addLogContents(ctx.getLogContents());
        todoLogDao.save(log);
    }

    void logTodoCompleted(TodoRequestContext ctx, List<Todo> todos) {
        ctx.addLogContent("state", PendingMessageStateEnum.COMPLETED);
        logTodosUpdated(ctx, todos);
    }

    void logSetTodoProcessing(TodoRequestContext ctx, List<Todo> todos) {
        ctx.addLogContent("state", PendingMessageStateEnum.PROCESSING);
        logTodosUpdated(ctx, todos);
    }

    void logTodoRollback(TodoRequestContext ctx, List<Todo> todos) {
        ctx.addLogContent("state", PendingMessageStateEnum.HAS_BEEN_SENT);
        logTodosUpdated(ctx, todos);
    }

    void logTodoRevoked(TodoRequestContext ctx, List<Todo> todos) {
        ctx.addLogContent("state", PendingMessageStateEnum.RETRACT);
        logTodosUpdated(ctx, todos);
    }

    void logTodoUpdated(TodoRequestContext ctx, Todo todo) {
        logTodosUpdated(ctx, Collections.singletonList(todo));
    }

    void logTodosUpdated(TodoRequestContext ctx, List<Todo> todos) {
        if (CollectionUtils.isEmpty(todos))
            return;
        TodoBusinesses businesses = todoBusinessDao.getBusinesses(todos);
        ArrayList<TodoLog> logs = new ArrayList<>();
        for (Todo todo : todos) {
            logs.add(createTodoLog(ctx, businesses, todo)
                    .addLogContents(ctx.getLogContents()));
        }
        todoLogDao.saveBatch(logs);
    }

    // !! factory

    private static TodoLog createBusinessLog(
            TodoRequestContext ctx, TodoBusiness business) {
        TodoLog log = new TodoLog();
        log.setLogType(TodoLogType.TODO_BUSINESS);
        log.setSrcTemplateCode(business.getTemplateCode());
        log.setTemplateCode(business.getTemplateCode());
        log.setIdentityCode("");
        log.setBizCode(business.getBizCode());
        log.setRequestNo(ctx.getRequestNo());
        log.setContext(ctx.getName());
        BizCategoryEnum category = business.getBizCategory();
        log.setCategory(category == null ? "" : category.name());
        return log;
    }

    private static TodoLog createTodoLog(
            TodoRequestContext ctx, TodoBusinesses businesses, Todo todo) {
        TodoLog log = new TodoLog();
        log.setLogType(todo.getType() == TodoType.EXECUTABLE
                ? TodoLogType.TODO
                : TodoLogType.TODO_COPIED_TO_ME);
        log.setSrcTemplateCode(todo.getSrcTemplateCode());
        log.setTemplateCode(todo.getTemplateCode());
        log.setIdentityCode(todo.getIdentityCode());
        log.setBizCode(todo.getBizCode());
        log.setSubBizCode(todo.getSubBizCode());
        log.setRequestNo(ctx.getRequestNo());
        log.setContext(ctx.getName());
        String category = businesses.findBusiness(todo)
                .map(TodoBusiness::getBizCategory)
                .map(Enum::name)
                .orElse("");
        log.setCategory(category);
        return log;
    }

}