package cn.forevermc.launcher.ctrl.pane;

import cn.forevermc.launcher.bean.Config;
import cn.forevermc.launcher.ctrl.Main;
import cn.forevermc.launcher.service.PageService;
import cn.forevermc.launcher.view.pages.CanvasProgressPane;
import com.google.gson.Gson;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.input.MouseEvent;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Paint;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import com.imyeyu.fx.task.RunAsync;
import com.imyeyu.fx.utils.AnimationRenderer;
import com.imyeyu.inject.annotation.Controller;
import com.imyeyu.inject.annotation.Inject;
import com.imyeyu.inject.annotation.SuperInject;
import com.imyeyu.utils.OS;

import java.util.ArrayList;
import java.util.List;

/**
 * 画板进度
 *
 * @author 夜雨
 * @since 2023-06-15 17:49
 */
@Slf4j
@Controller
@SuperInject
public class CanvasProgress extends CanvasProgressPane implements OS.FileSystem {

	private static final String PACK_CACHE_PATH = "etc" + SEP + "pack";

	@Inject
	private Config config;

	@Inject
	private Main main;

	@Inject
	private Gson gson;

	@Inject
	private Dialog dialog;

	@Inject
	private PageService pageService;

	@Inject
	private ObjectProperty<MediaPlayer> bgmPlayer;

	private final List<Pixel> pixelList;
	private final DoubleProperty progress;
	private final AnimationRenderer renderer;
	private final ObjectProperty<Paint> color;
	private final ObjectProperty<Paint> backgroundColor;

	@Getter
	private RunAsync<?> task;

	private int i = 0;

	public CanvasProgress() {
		pixelList = new ArrayList<>();
		progress = new SimpleDoubleProperty(0);
		color = new SimpleObjectProperty<>(Colorful.PINK);
		backgroundColor = new SimpleObjectProperty<>(Colorful.BLACK);

		// 图形进度
		canvas.visibleProperty().bind(progress.isNotEqualTo(-1));
		canvas.managedProperty().bind(canvas.visibleProperty());

		int unitSize = 4;
		int center = (SIZE - 4) / 2;
		// 层级
		int layerMax = center / unitSize;
		for (int layer = 0; layer <= layerMax; layer++) {
			// 上
			for (int i = -layer + 1; i <= layer; i++) {
				int x = center + i * unitSize;
				int y = center - layer * unitSize;
				pixelList.add(new Pixel(x, y));
			}
			// 右
			for (int i = -layer; i <= layer; i++) {
				int x = center + layer * unitSize;
				int y = center + i * unitSize;
				pixelList.add(new Pixel(x, y));
			}
			// 下
			for (int i = -layer; i <= layer; i++) {
				int x = center - i * unitSize;
				int y = center + layer * unitSize;
				pixelList.add(new Pixel(x, y));
			}
			// 左
			for (int i = -layer; i <= layer + 1; i++) {
				int x = center - layer * unitSize;
				int y = center - i * unitSize;
				pixelList.add(new Pixel(x, y));
			}
		}

		// 图形进度渲染
		renderer = new AnimationRenderer();
		renderer.addRenderCallback(aDouble -> {
			while (1D * i / pixelList.size() < progress.get() && i < pixelList.size()) {
				Pixel pixel = pixelList.get(i);
				g.setFill(color.get());
				g.fillRect(pixel.x, pixel.y, 4, 4);
				i++;
			}
		});

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

		// 背景音乐
		bgmToggle.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
			if (bgmPlayer.get() == null) {
				e.consume();
			}
		});
		bgmToggle.selectedProperty().addListener((obs, o, isSelected) -> {
			MediaPlayer player = bgmPlayer.get();
			if (player != null) {
				if (isSelected) {
					player.play();
				} else {
					player.pause();
				}
			}
		});

		// 取消
		cancel.setOnAction(e -> task.interrupt());
	}

	@Override
	public void onShow() {
		reset();
		bgmToggle.visibleProperty().bind(config.getMain().getBgmVolume().greaterThan(0));
		renderer.start();

		if (progress.isBound()) {
			progress.unbind();
		}
		log.info("start downloading: ");
		task.messageProperty().addListener((obs, o, compressedFile) -> subLabel.setText(compressedFile));
		progress.bind(task.progressProperty());
		task.start();
	}

	@Override
	public void onHide() {
		renderer.stop();
		progress.unbind();
		label.setText("");
		subLabel.setText("");
	}

	public void reset() {
		i = 0;
		{
			g.setFill(backgroundColor.get());
			g.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
			g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
		}
	}

	public <T> void setTask(RunAsync<T> task) {
		this.task = task;
	}

	public void setCanCancel(boolean canCancel) {
		cancel.setDisable(!canCancel);
	}

	public BooleanBinding canCancelProperty() {
		return cancel.disableProperty().not();
	}

	public void setColor(Paint color) {
		this.color.set(color);
	}

	public ObjectProperty<Paint> colorProperty() {
		return color;
	}

	public void setBackgroundColor(Paint backgroundColor) {
		this.backgroundColor.set(backgroundColor);
	}

	public ObjectProperty<Paint> backgroundColorProperty() {
		return backgroundColor;
	}

	/**
	 *
	 *
	 * @author 夜雨
	 * @since 2024-07-01 23:24
	 */
	@AllArgsConstructor
	private static class Pixel {

		int x;

		int y;
	}
}
