package com.ecep.contract.task;

import java.util.Locale;
import java.util.logging.Level;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;

import com.ecep.contract.Desktop;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.SpringApp;
import com.ecep.contract.model.Employee;
import com.ecep.contract.service.CompanyService;
import com.ecep.contract.service.EmployeeService;
import com.ecep.contract.service.SysConfService;

import javafx.application.Platform;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Task;
import javafx.scene.control.ListCell;
import lombok.Setter;

public abstract class Tasker<T> extends Task<T> {
    private static final Logger logger = LoggerFactory.getLogger(Tasker.class);
    @Setter
    protected java.util.function.Predicate<Message> messageHandler;
    private Employee currentUser;
    @Setter
    private CompanyService companyService;
    @Setter
    private EmployeeService employeeService;
    @Setter
    private SysConfService confService;

    public SysConfService getConfService() {
        if (confService == null) {
            confService = getBean(SysConfService.class);
        }
        return confService;
    }

    public CompanyService getCompanyService() {
        if (companyService == null) {
            companyService = getBean(CompanyService.class);
        }
        return companyService;
    }

    public EmployeeService getEmployeeService() {
        if (employeeService == null) {
            employeeService = getBean(EmployeeService.class);
        }
        return employeeService;
    }

    protected <K> K getBean(Class<K> requiredType) throws BeansException {
        return SpringApp.getBean(requiredType);
    }

    public Employee getCurrentUser() {
        if (currentUser == null) {
            currentUser = getEmployeeService().findById(Desktop.instance.getActiveEmployeeId());
        }
        return currentUser;
    }

    @Override
    protected T call() throws Exception {
        MessageHolderImpl holder = new MessageHolderImpl();
        try {
            return execute(holder);
        } catch (Exception e) {

            holder.error(e.getMessage());
            logger.error(e.getMessage(), e);
            throw e;
        }
    }

    protected abstract T execute(MessageHolder holder) throws Exception;

    @Override
    protected void updateMessage(String message) {
        updateMessage(Level.INFO, message);
    }

    protected void updateMessage(Level level, String message) {
        if (messageHandler != null) {
            if (messageHandler.test(new Message(level, message))) {
                return;
            }
        }
        super.updateMessage(message);
    }

    protected void skipUpdateCheckUpdateMessage(String message) {
        if (Platform.isFxApplicationThread()) {
            ((StringProperty) messageProperty()).set(message);
        } else {
            Platform.runLater(() -> ((StringProperty) messageProperty()).set(message));
        }
    }

    @Override
    protected void scheduled() {
        super.scheduled();
        updateMessage(Level.FINE, "任务进入调度器");
    }

    @Override
    protected void running() {
        super.running();
        updateMessage(Level.FINE, "任务开始执行");
    }

    @Override
    protected void cancelled() {
        super.cancelled();
        updateMessage(Level.SEVERE, "任务被取消");
    }

    @Override
    protected void failed() {
        super.failed();
        Throwable exception = getException();
        if (exception == null) {
            updateMessage(Level.SEVERE, "任务执行失败");
        } else {
            updateMessage(Level.SEVERE, "任务执行失败:" + exception.getMessage());
            if (logger.isErrorEnabled()) {
                logger.error(exception.getMessage(), exception);
            }
        }
    }

    @Override
    protected void succeeded() {
        super.succeeded();
        updateMessage(Level.FINE, "任务执行完毕");
    }

    public static class MessageListCell extends ListCell<Message> {
        @Override
        protected void updateItem(Message item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null || empty) {
                setText(null);
                getStyleClass().clear();
            } else {
                setText(item.getMessage());
                getStyleClass().removeIf(s -> s.startsWith("row-"));
                getStyleClass().add("row-" + item.getLevel().getName().toLowerCase());
            }
        }
    }

    /**
     * 错误消息处理
     */
    public class MessageHolderImpl implements MessageHolder {
        public MessageHolderImpl() {
        }

        @Override
        public void addMessage(Level level, String message) {
            updateMessage(level, message);
        }
    }

    public Locale getLocale() {
        return Desktop.instance.getActiveEmployee().localeProperty().get();
    }
}
