package cn.forevermc.launcher.ctrl.pane;

import cn.forevermc.launcher.bean.Pack;
import cn.forevermc.launcher.bean.Page;
import cn.forevermc.launcher.service.GameService;
import cn.forevermc.launcher.service.PageService;
import cn.forevermc.launcher.util.Path;
import cn.forevermc.launcher.util.Resources;
import cn.forevermc.launcher.view.pages.PackSelectPane;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.imyeyu.compress.CompressType;
import com.imyeyu.compress.Decompressor;
import com.imyeyu.fx.task.RunAsync;
import com.imyeyu.fx.ui.TimiFXUI;
import com.imyeyu.inject.annotation.Controller;
import com.imyeyu.inject.annotation.Inject;
import com.imyeyu.inject.annotation.InvokeForInjected;
import com.imyeyu.inject.annotation.SuperIOC;
import com.imyeyu.inject.annotation.SuperInject;
import com.imyeyu.io.IO;
import com.imyeyu.io.IOSize;
import com.imyeyu.io.IOSpeedService;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.CallbackArg;
import com.imyeyu.network.Network;
import com.imyeyu.network.ProgressiveRequest;
import com.imyeyu.network.TimiRequest;
import com.imyeyu.utils.OS;
import javafx.application.Platform;
import javafx.scene.paint.Paint;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.List;

/**
 * 整合版选择控制
 *
 * @author 夜雨
 * @since 2023-06-13 23:32
 */
@Slf4j
@SuperIOC
@Controller
@SuperInject
public class PackSelect extends PackSelectPane implements OS.FileSystem {

	/** 整合版列表接口 */
	private static final String API = Resources.TIMI_SERVER_API + "/fmc/pack/list";

	/** 附件信息接口 */
	private static final String ATTACH_API = Resources.TIMI_SERVER_API + "/attachment/%s";

	/** 附件下载接口 */
	private static final String ATTACH_DL_API = Resources.TIMI_SERVER_API + "/attachment/download/%s";

	@Inject
	private Gson gson;

	@Inject
	private Dialog dialog;

	@Inject
	private PageService pageService;

	@Inject
	private GameService gameService;

	@Inject
	private CanvasProgress canvasProgress;

	@Inject
	private IOSpeedService.Item ioSpeedItem;

	public PackSelect() {
		// 安装
		install.setOnAction(e -> {
			String[] installedPacks = gameService.listGames();
			Pack pack = packListPane.getSelectionModel().getSelectedItem();
			Pack.Source source = sourceListPane.getSelectionModel().getSelectedItem();
			if (installedPacks != null) {
				for (int i = 0; i < installedPacks.length; i++) {
					if (installedPacks[i].trim().equals(pack.getName().trim())) {
						File json = new File(Path.ABS_PACK + installedPacks[i] + SEP + installedPacks[i] + ".json");
						if (json.exists() && json.isFile() && 0 < json.length()) {
							// 已存在安装
							dialog.setTitle(TimiFXUI.MULTILINGUAL.text("install.fail"));
							dialog.setContent(TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.download.fmc.exist_warning", pack.getName()));
							dialog.setConfirmEvent(() -> pageService.to(Page.GAME_SELECT));
							dialog.eject();
							return;
						}
					}
				}
			}
			canvasProgress.setTask(new RunAsync<String>() {

				final CallbackArg<Double> DL_SPEED = d -> Platform.runLater(() -> canvasProgress.getSubLabel().setText(IOSize.format(d, IOSize.Unit.MB) + "/s"));

				@Override
				protected String call() throws Exception {
					progress(0);

					String url = switch (source.getType()) {
						case URL -> source.getData();
						case ATTACH -> ATTACH_DL_API.formatted(source.getData());
					};
					String fileName = switch (source.getType()) {
						case URL -> Network.uriFileName(source.getData());
						case ATTACH -> TimiRequest.<JsonObject>get(ATTACH_API.formatted(source.getData())).result().get("name").getAsString();
					};
					File compressedFile = new File("etc" + SEP + fileName);
					if (!compressedFile.exists() || compressedFile.length() != pack.getSize()) {
						// 下载文件
						log.info("download remote pack: {}", url);
						update("DOWNLOAD");
						ProgressiveRequest.get(url, (total, read, now) -> {
							progress(1D * read / pack.getSize());
							ioSpeedItem.push(now);
							return !isInterrupted;
						}).toFile(compressedFile);
					}
					if (!isInterrupted) {
						// 解压文件
						log.info("decompress pack file: {}", compressedFile.getAbsolutePath());
						progress(0);
						update("DECOMPRESS");
						Decompressor decompressor = CompressType.fromFile(compressedFile);
						decompressor.setFileCallback(file -> message(file.getName()));
						decompressor.setProgressCallback(this::progress);
						decompressor.run(compressedFile, Path.ABS_PACK + pack.getName());
						IO.destroy(compressedFile);

						// 初始配置
						File optionFile = new File(Path.ABS_PACK + pack.getName() + SEP + pack.getName() + ".yaml");
						IO.toFile(optionFile, pack.getDefOption());
					}
					return null;
				}

				@Override
				protected void onUpdate(String status) {
					if (TimiJava.isNotEmpty(status)) {
						switch (status) {
							case "DOWNLOAD" -> {
								ioSpeedItem.addBufferListener(DL_SPEED);

								canvasProgress.setCanCancel(true);
								canvasProgress.setBackgroundColor(Colorful.BLACK);
								canvasProgress.setColor(Paint.valueOf("#AAA"));
								canvasProgress.reset();
							}
							case "DECOMPRESS" -> {
								ioSpeedItem.removeBufferListener(DL_SPEED);

								canvasProgress.setCanCancel(false);
								canvasProgress.setBackgroundColor(Paint.valueOf("#AAA"));
								canvasProgress.setColor(Paint.valueOf("#0A0"));
								canvasProgress.reset();
							}
						}
					}
				}

				@Override
				protected void onFinish() {
					reset();
					if (isInterrupted) {
						log.info("install be cancel");
						pageService.to(Page.PACK_SELECT);
					} else {
						// 安装完成
						log.info("installed pack succeed");
						dialog.setContent(TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.download.fmc.succeed", pack.getName()));
						dialog.setConfirmEvent(() -> pageService.to(Page.GAME_SELECT));
						dialog.eject();
					}
				}

				@Override
				protected void onException(Throwable e) {
					log.error("install remote pack error", e);
					dialog.setContent(TimiFXUI.MULTILINGUAL.text("error") + ": " + e.getMessage());
					dialog.setConfirmEvent(() -> pageService.to(Page.PACK_SELECT));
					dialog.eject();
				}
			});
			canvasProgress.setCanCancel(true);
			canvasProgress.setBackgroundColor(Colorful.BLACK);
			canvasProgress.setColor(Paint.valueOf("#AAA"));
			canvasProgress.getLabel().setText(TimiFXUI.MULTILINGUAL.textArgs("fmc.launcher.download.fmc.downloading", pack.getName()));
			pageService.to(Page.CANVAS_PROGRESS);
		});

		// 返回
		back.setOnAction(e -> pageService.to(Page.GAME_SELECT));
	}

	@InvokeForInjected
	private void injected() {
		// 下载源列表更新
		packListPane.getSelectionModel().selectedItemProperty().addListener((obs, o, newSelectedItem) -> {
			if (newSelectedItem == null) {
				sourceListPane.getItems().clear();
			} else {
				List<Pack.Source> sources = newSelectedItem.getSourceList();
				sourceListPane.getItems().setAll(sources);
				for (int i = 0; i < sources.size(); i++) {
					if (sources.get(i).isDefault()) {

						sourceListPane.getSelectionModel().select(sources.get(i));
						break;
					}
				}
			}
		});
	}

	@Override
	public void onShow() {
		packListPane.setLoading(true);
		sourceListPane.setLoading(true);
		new RunAsync<List<Pack>>() {

			@Override
			protected List<Pack> call() throws Exception {
				// 获取整合版列表
				return TimiRequest.<List<Pack>>post(API).result();
			}

			@Override
			protected void onFinish(List<Pack> packs) {
				packListPane.getItems().setAll(packs);
			}

			@Override
			protected void onException(Throwable e) {
				log.error("list remote pack error", e);
				dialog.setContent(TimiFXUI.MULTILINGUAL.text("fmc.launcher.download.fmc.error"));
				dialog.setConfirmEvent(() -> pageService.to(Page.GAME_SELECT));
				dialog.eject();
			}

			@Override
			protected void onFinally() {
				packListPane.setLoading(false);
				sourceListPane.setLoading(false);
			}
		}.start();
	}

	@Override
	public void onHide() {
		packListPane.getItems().clear();
		sourceListPane.getItems().clear();
	}
}
