package com.imyeyu.fx.ui.components;

import com.imyeyu.fx.task.RunAsync;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.utils.Encoder;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;

/**
 * 版本标签，此组件用于显示版本、检查更新和可更新时点击去向，目前可能只适合我使用
 *
 * @author 夜雨
 * @since 2022-02-19 18:42
 */
public abstract class VersionLabel<T> extends VBox implements TimiFXUI, TimiFXUI.Colorful {

	/**
	 * 状态
	 *
	 * @author 夜雨
	 * @since 2022-11-27 16:13
	 */
	@AllArgsConstructor
	protected enum Status {

		/** 一般 */
		NORMAL(BLACK),

		/** 正在检查 */
		CHECKING(ORANGE),

		/** 存在更新 */
		HAS_UPDATE(GREEN),

		/** 错误 */
		ERROR(RED);

		final Color textColor;
	}

	/** 更新链接 */
	@Setter
	@Getter
	protected String updateURL;

	/** 版本标签 */
	protected Label version;

	/** 其他内容标签 */
	protected Label content;

	/** 状态 */
	protected ObjectProperty<Status> status;

	/** 默认构造 */
	public VersionLabel() {
		this("");
	}

	/**
	 * 默认构造
	 *
	 * @param text 显示版本
	 */
	public VersionLabel(String text) {
		status = new SimpleObjectProperty<>(Status.NORMAL);

		version = new Label();
		version.setText(text);
		version.setWrapText(true);
		version.textFillProperty().bind(Bindings.createObjectBinding(() -> status.get().textColor, status));

		content = new Label();
		content.managedProperty().bind(content.textProperty().isNotEmpty());

		setSpacing(3);
		setAlignment(Pos.CENTER);
		getChildren().addAll(version, content);
	}

	/**
	 * 检查版本更新
	 *
	 * @param nowVersion 当前版本
	 */
	public void checkVersion(String nowVersion) {
		status.set(Status.CHECKING);
		version.setCursor(Cursor.DEFAULT);
		version.setOnMouseClicked(null);

		// ---------- 事件 ----------

		new RunAsync<T>() {

			@Override
			protected T call() {
				return VersionLabel.this.run();
			}

			@Override
			protected void onFinish(T t) {
				try {
					String version = onReturn(t);
					if (version.equals(nowVersion)) {
						// 无新版本
						VersionLabel.this.version.setText(nowVersion);
						status.set(Status.NORMAL);
					} else {
						// 存在新版本
						VersionLabel.this.version.setText(VersionLabel.this.updateText(version));
						VersionLabel.this.version.setCursor(Cursor.HAND);
						VersionLabel.this.version.underlineProperty().bind(VersionLabel.this.version.hoverProperty());
						VersionLabel.this.version.setOnMouseClicked(event -> {
							try {
								Desktop dp = Desktop.getDesktop();
								if (dp.isSupported(Desktop.Action.BROWSE)) {
									dp.browse(URI.create(Encoder.url(updateURL)));
								}
							} catch (IOException e) {
								e.printStackTrace();
							}
						});
						status.set(Status.HAS_UPDATE);
					}
				} catch (RuntimeException e) {
					version.setText(e.getMessage());
					status.set(Status.ERROR);
				}
			}

			@Override
			protected void onException(Throwable e) {
				version.setText(TimiFXUI.MULTILINGUAL.text("version.fail"));
				version.setOnMouseClicked(event -> checkVersion(nowVersion));
				e.printStackTrace();
			}
		}.start();
	}

	/**
	 * 执行查询版本
	 *
	 * @return 执行返回
	 */
	protected abstract T run() throws RuntimeException;

	/**
	 * 执行返回
	 *
	 * @param t 返回数据
	 * @return 具体版本号
	 */
	protected abstract String onReturn(T t) throws RuntimeException;

	/**
	 * 存在更新时执行
	 *
	 * @param newVersion 版本
	 * @return 显示文本
	 */
	protected abstract String updateText(String newVersion);

	/**
	 * 执行异常的显示文本
	 *
	 * @param e 异常
	 * @return 显示文本
	 */
	protected abstract String failText(Throwable e);
}
