package com.imyeyu.fx.ui.components;

import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.java.ref.Ref;
import com.sun.javafx.scene.control.skin.Utils;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ListChangeListener;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Skin;
import javafx.scene.control.TextArea;
import javafx.scene.control.skin.TextAreaSkin;
import javafx.scene.layout.Region;
import javafx.scene.paint.Paint;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;

import java.util.List;

/**
 * 可选中的标签组件，实际上是无样式文本域，此组件适应布局最大宽度
 *
 * @author 夜雨
 * @since 2022-01-29 01:24
 */
public class SelectableLabel extends TextArea implements TimiFXUI, TimiFXUI.Colorful {

	private static final String STYLE_CLASS = "selectable-label";

	private final ObjectProperty<Paint> textFillProperty;
	private final ObjectProperty<TextAlignment> textAlignmentProperty;

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

	/**
	 * 构造器
	 *
	 * @param text 文本内容
	 */
	public SelectableLabel(String text) {
		super(text);

		textFillProperty = new SimpleObjectProperty<>(BLACK);
		textAlignmentProperty = new SimpleObjectProperty<>(TextAlignment.LEFT);

		setCursor(Cursor.TEXT);
		setEditable(false);
		setWrapText(true);
		setMaxWidth(Double.MAX_VALUE);
		setMinSize(Double.MIN_VALUE, Double.MIN_VALUE);
		setPrefHeight(0);
		setPrefSize(0, 0);
		getStyleClass().setAll(STYLE_CLASS, CSS.MINECRAFT);

		focusedProperty().addListener((obs, o, isFocused) -> {
			if (!isFocused) {
				deselect();
			}
		});
	}

	@Override
	protected Skin<?> createDefaultSkin() {
		Skin<?> defaultSkin = super.createDefaultSkin();
		if (defaultSkin instanceof TextAreaSkin skin) {
			try {
				ScrollPane sp = Ref.getFieldValue(skin, "scrollPane", ScrollPane.class);
				sp.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
				if (sp.getContent() instanceof Region region) {
					region.heightProperty().addListener((obs, o, newHeight) -> Platform.runLater(() -> {
						// 需要 runLater，因为是 Region 适应 Skin 变化
						setPrefHeight(newHeight.doubleValue());
					}));
				}
				Group paragraphNodes = Ref.getFieldValue(skin, "paragraphNodes", Group.class);
				paragraphNodes.getChildren().addListener((ListChangeListener<Node>) c -> {
					if (c.next()) {
						if (c.wasAdded()) {
							bindTextStyle(c.getAddedSubList());
						}
					}
				});
				bindTextStyle(paragraphNodes.getChildren());
				widthProperty().addListener((obs, oldValue, newValue) -> {
					if (oldValue.doubleValue() < newValue.doubleValue()) {
						if (paragraphNodes.getChildren().getFirst() instanceof Text text) {
							setPrefHeight(Utils.computeTextHeight(getFont(), getText(), getWidth(), text.getBoundsType()));
						}
					}
				});
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			}
		}
		return defaultSkin;
	}

	@Override
	public String getUserAgentStylesheet() {
		return SelectableLabel.class.getResource(RESOURCE + "style/components/selectable-label.css").toExternalForm();
	}

	/**
	 * 绑定文本样式
	 *
	 * @param list 文本节点，必须是 {@link Text}
	 */
	private void bindTextStyle(List<? extends Node> list) {
		for (Node node : list) {
			if (node instanceof Text text) {
				text.fillProperty().bind(textFillProperty);
				text.textAlignmentProperty().bind(textAlignmentProperty);
			}
		}
	}

	/**
	 * 设置字体颜色
	 *
	 * @param textFill 字体颜色
	 */
	public void setTextFill(Paint textFill) {
		this.textFillProperty.set(textFill);
	}

	/**
	 * 获取字体颜色
	 *
	 * @return 字体颜色
	 */
	public Paint getTextFill() {
		return textFillProperty.get();
	}

	/**
	 * 获取字体颜色绑定
	 *
	 * @return 字体颜色绑定
	 */
	public ObjectProperty<Paint> textFillProperty() {
		return textFillProperty;
	}

	/**
	 * 设置文本对齐方式
	 *
	 * @param textAlignment 文本对齐方式
	 */
	public void setTextAlignment(TextAlignment textAlignment) {
		this.textAlignmentProperty.set(textAlignment);
	}

	/**
	 * 获取文本对齐方式
	 *
	 * @return 文本对齐方式
	 */
	public TextAlignment getTextAlignment() {
		return textAlignmentProperty.get();
	}

	/**
	 * 获取文本对齐方式绑定
	 *
	 * @return 文本对齐方式绑定
	 */
	public ObjectProperty<TextAlignment> textAlignmentProperty() {
		return textAlignmentProperty;
	}
}
