package com.imyeyu.fx.ui.components;

import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.utils.Time;
import javafx.animation.PauseTransition;
import javafx.application.Platform;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.scene.control.Label;
import javafx.scene.paint.Paint;
import javafx.util.Duration;

/**
 * 提示标签，可以临时显示提示内容，经过指定时间后自动恢复原内容。
 * <p>
 * 此组件是线程安全的，可以从任意线程调用 {@link #tips(String)} 方法。
 * 如果在提示期间再次调用 tips 方法，会重置计时器并显示新的提示内容，
 * 恢复时仍然恢复为最初的原始内容。
 * </p>
 *
 * <pre>{@code
 * LabelTips label = new LabelTips("默认内容");
 * label.tips("操作成功！");           // 使用默认 3 秒
 * label.tips("保存完成！", 5000);     // 指定 5 秒
 * }</pre>
 *
 * @author 夜雨
 * @since 2025-01-14
 */
public class LabelTips extends Label implements TimiFXUI.Colorful {

	/** 默认提示持续时间（毫秒） */
	public static final long DEFAULT_DURATION = Time.S * 5;

	/** 信息提示颜色 */
	public static final Paint INFO_TEXT_FILL = BLUE;

	/** 警告提示颜色 */
	public static final Paint WARN_TEXT_FILL = ORANGE;

	/** 错误提示颜色 */
	public static final Paint ERROR_TEXT_FILL = RED;

	/** 提示持续时间（毫秒） */
	protected LongProperty duration;

	/** 原始内容，提示结束后恢复 */
	private volatile String originalText;

	/** 原始颜色，提示结束后恢复 */
	private volatile Paint originalTextFill;

	/** 定时器，用于恢复原内容 */
	private PauseTransition transition;

	/** 同步锁 */
	private final Object lock = new Object();

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

	/**
	 * 标准构造器
	 *
	 * @param text 标签初始文本
	 */
	public LabelTips(String text) {
		super(text);
		this.duration = new SimpleLongProperty(DEFAULT_DURATION);
	}

	/**
	 * 显示提示内容，使用默认持续时间
	 *
	 * @param content 提示内容
	 */
	public void tips(String content) {
		tips(content, duration.get());
	}

	/**
	 * 显示提示内容，指定持续时间
	 *
	 * @param content 提示内容
	 * @param millis  持续时间（毫秒）
	 */
	public void tips(String content, long millis) {
		tips(content, Duration.millis(millis));
	}

	/**
	 * 显示提示内容，指定持续时间
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 */
	public void tips(String content, Duration duration) {
		tips(content, duration, null);
	}

	/**
	 * 显示提示内容，指定持续时间与颜色
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 * @param textFill 文本颜色
	 */
	public void tips(String content, Duration duration, Paint textFill) {
		if (Platform.isFxApplicationThread()) {
			doTips(content, duration, textFill);
		} else {
			Platform.runLater(() -> doTips(content, duration, textFill));
		}
	}

	/**
	 * 显示信息提示内容，使用默认持续时间
	 *
	 * @param content 提示内容
	 */
	public void info(String content) {
		info(content, duration.get());
	}

	/**
	 * 显示信息提示内容，指定持续时间
	 *
	 * @param content 提示内容
	 * @param millis  持续时间（毫秒）
	 */
	public void info(String content, long millis) {
		info(content, Duration.millis(millis));
	}

	/**
	 * 显示信息提示内容，指定持续时间
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 */
	public void info(String content, Duration duration) {
		tips(content, duration, INFO_TEXT_FILL);
	}

	/**
	 * 显示警告提示内容，使用默认持续时间
	 *
	 * @param content 提示内容
	 */
	public void warn(String content) {
		warn(content, duration.get());
	}

	/**
	 * 显示警告提示内容，指定持续时间
	 *
	 * @param content 提示内容
	 * @param millis  持续时间（毫秒）
	 */
	public void warn(String content, long millis) {
		warn(content, Duration.millis(millis));
	}

	/**
	 * 显示警告提示内容，指定持续时间
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 */
	public void warn(String content, Duration duration) {
		tips(content, duration, WARN_TEXT_FILL);
	}

	/**
	 * 显示错误提示内容，使用默认持续时间
	 *
	 * @param content 提示内容
	 */
	public void error(String content) {
		error(content, duration.get());
	}

	/**
	 * 显示错误提示内容，指定持续时间
	 *
	 * @param content 提示内容
	 * @param millis  持续时间（毫秒）
	 */
	public void error(String content, long millis) {
		error(content, Duration.millis(millis));
	}

	/**
	 * 显示错误提示内容，指定持续时间
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 */
	public void error(String content, Duration duration) {
		tips(content, duration, ERROR_TEXT_FILL);
	}

	/**
	 * 执行提示逻辑，必须在 FX 线程调用
	 *
	 * @param content  提示内容
	 * @param duration 持续时间
	 */
	private void doTips(String content, Duration duration, Paint textFill) {
		synchronized (lock) {
			// 停止之前的定时器
			if (transition != null) {
				transition.stop();
			}

			// 仅在首次调用时保存原始内容
			if (originalText == null) {
				originalText = getText();
				originalTextFill = getTextFill();
			}

			// 设置提示内容
			setText(content);
			if (textFill != null) {
				setTextFill(textFill);
			} else {
				setTextFill(originalTextFill);
			}

			// 创建定时器
			transition = new PauseTransition(duration);
			transition.setOnFinished(e -> {
				synchronized (lock) {
					setText(originalText);
					setTextFill(originalTextFill);
					originalText = null;
					originalTextFill = null;
					transition = null;
				}
			});
			transition.play();
		}
	}

	/**
	 * 立即恢复原始内容，取消正在进行的提示
	 */
	public void restore() {
		if (Platform.isFxApplicationThread()) {
			doRestore();
		} else {
			Platform.runLater(this::doRestore);
		}
	}

	/**
	 * 执行恢复逻辑，必须在 FX 线程调用
	 */
	private void doRestore() {
		synchronized (lock) {
			if (transition != null) {
				transition.stop();
				transition = null;
			}
			if (originalText != null) {
				setText(originalText);
				setTextFill(originalTextFill);
				originalText = null;
				originalTextFill = null;
			}
		}
	}

	/**
	 * 检查当前是否正在显示提示
	 *
	 * @return 如果正在显示提示返回 true
	 */
	public boolean isTipping() {
		synchronized (lock) {
			return originalText != null;
		}
	}

	/**
	 * 获取默认提示持续时间
	 *
	 * @return 持续时间（毫秒），默认 {@value #DEFAULT_DURATION}
	 */
	public long getDuration() {
		return duration.get();
	}

	/**
	 * 设置默认提示持续时间
	 *
	 * @param millis 持续时间（毫秒）
	 */
	public void setDuration(long millis) {
		this.duration.set(millis);
	}

	/**
	 * 获取持续时间属性
	 *
	 * @return 持续时间属性
	 */
	public LongProperty durationProperty() {
		return duration;
	}
}
