package com.ecep.contract.vm;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.ecep.contract.Desktop;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.controller.CurrentEmployeeInitialedEvent;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.EmployeeRole;
import com.ecep.contract.service.EmployeeService;

import javafx.application.Platform;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.util.converter.CurrencyStringConverter;
import javafx.util.converter.LocalDateStringConverter;
import javafx.util.converter.LocalDateTimeStringConverter;
import javafx.util.converter.NumberStringConverter;
import lombok.ToString;

/**
 * 当前登录用户
 */
@ToString(callSuper = false, exclude = "roles")
public class CurrentEmployee extends EmployeeViewModel {
    private static final Logger logger = LoggerFactory.getLogger(CurrentEmployee.class);
    /**
     * 语言环境
     */
    private SimpleObjectProperty<Locale> locale = new SimpleObjectProperty<>(Locale.getDefault());
    /**
     * 角色
     */
    private SimpleListProperty<EmployeeRole> roles = new SimpleListProperty<>(FXCollections.observableArrayList());

    private DateTimeFormatter dateFormatter = DateTimeFormatter
            .ofPattern(MyDateTimeUtils.DEFAULT_DATE_FORMAT_PATTERN);
    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter
            .ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN);
    private DateTimeFormatter timeFormatter = DateTimeFormatter
            .ofPattern(MyDateTimeUtils.DEFAULT_TIME_FORMAT_PATTERN);

    private LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter(
            dateFormatter, null);
    private LocalDateTimeStringConverter localDateTimeStringConverter = new LocalDateTimeStringConverter(
            dateTimeFormatter, null);

    private NumberStringConverter numberStringConverter = new NumberStringConverter("#,##0.00");
    private CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter("#,##0.00");

    /**
     * 是否系统管理员
     */
    public boolean isSystemAdministrator() {
        return roles.stream().anyMatch(EmployeeRole::isSystemAdministrator);
    }

    /**
     * 语言环境属性
     */
    public SimpleObjectProperty<Locale> localeProperty() {
        return locale;
    }

    /**
     * 角色属性
     */
    public SimpleListProperty<EmployeeRole> rolesProperty() {
        return roles;
    }

    @Override
    protected void updateFrom(Employee v) {
        super.updateFrom(v);

        // 根据用户的个人配置修改
        if (StringUtils.hasText(v.getLocale())) {
            try {
                localeProperty().set(Locale.forLanguageTag(v.getLocale()));
            } catch (Exception e) {
                handleException("解析设置用户区域设置失败，" + v.getLocale(), e);
            }
        }
        if (StringUtils.hasText(v.getDateFormatter())) {
            try {
                dateFormatter = DateTimeFormatter.ofPattern(v.getDateFormatter());
                localDateStringConverter = new LocalDateStringConverter(dateFormatter, null);
            } catch (Exception e) {
                handleException("解析设置用户日期格式失败，" + v.getDateFormatter(), e);
            }
        }
        if (StringUtils.hasText(v.getDateTimeFormatter())) {
            try {
                dateTimeFormatter = DateTimeFormatter.ofPattern(v.getDateTimeFormatter());
                localDateTimeStringConverter = new LocalDateTimeStringConverter(dateTimeFormatter, null);
            } catch (Exception e) {
                handleException("解析设置用户日期时间格式失败，" + v.getDateTimeFormatter(), e);
            }
        }

        if (StringUtils.hasText(v.getNumberFormatter())) {
            try {
                numberStringConverter = new NumberStringConverter(localeProperty().get(), v.getNumberFormatter());
            } catch (Exception e) {
                handleException("解析设置用户数字格式失败，" + v.getNumberFormatter(), e);
            }
        }

        if (StringUtils.hasText(v.getCurrencyFormatter())) {
            try {
                currencyStringConverter = new CurrencyStringConverter(localeProperty().get(), v.getCurrencyFormatter());
            } catch (Exception e) {
                handleException("解析设置用户货币格式失败，" + v.getCurrencyFormatter(), e);
            }
        }
    }

    /**
     * 初始化
     */
    public CompletableFuture<Void> initialize() {
        CompletableFuture<Void> future = new CompletableFuture<>();
        ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
        /**
         * 异步初始化当前用户
         * 1. 从数据库中查询当前用户
         * 2. 从数据库中查询当前用户的角色
         * 3. 更新当前用户的信息
         * 4. 更新当前用户的角色
         */
        executorService.submit(() -> {
            // issue #1 sss 2020-07-05
            EmployeeService employeeService = SpringApp.getBean(EmployeeService.class);
            Employee employee = employeeService.findById(Desktop.instance.getActiveEmployeeId());
            List<EmployeeRole> roles = employeeService.getRolesByEmployeeId(employee.getId());
            Platform.runLater(() -> {
                update(employee);
                rolesProperty().setAll(roles);
                // 发布事件
                SpringApp.context.publishEvent(new CurrentEmployeeInitialedEvent(this));
                future.complete(null);
            });
        });
        /**
         * 定时更新用户活动状态
         */
        executorService.scheduleWithFixedDelay(() -> {
            try {
                // SpringApp.getBean(EmployeeService.class).updateActive(Desktop.instance.getSessionId());
            } catch (Exception e) {
                if (logger.isErrorEnabled()) {
                    logger.error("updateActive:{}", e.getMessage(), e);
                }
            }
        }, 10, 10, TimeUnit.SECONDS);
        return future;
    }

    private void handleException(String msg, Exception e) {
        logger.warn(msg, e);
    }

    public LocalDateStringConverter getLocalDateStringConverter() {
        return localDateStringConverter;
    }

    public LocalDateTimeStringConverter getLocalDateTimeStringConverter() {
        return localDateTimeStringConverter;
    }

    public NumberStringConverter getNumberStringConverter() {
        return numberStringConverter;
    }

    public CurrencyStringConverter getCurrencyStringConverter() {
        return currencyStringConverter;
    }
}
