using Cryville.Common;
using Cryville.Common.Unity;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using Logger = Cryville.Common.Logger;

namespace Cryville.Crtr.Browsing {
	internal class LegacyResourceManager : IResourceManager<ChartDetail> {
		private readonly string _rootPath;
		private DirectoryInfo cd;
		private DirectoryInfo[] items = new DirectoryInfo[0];
		public string[] CurrentDirectory { get; private set; }

		static readonly Dictionary<string, List<ResourceConverter>> converters
			= new Dictionary<string, List<ResourceConverter>>();

		public LegacyResourceManager(string rootPath) {
			_rootPath = rootPath;
		}

		static LegacyResourceManager() {
			foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
				foreach (var type in asm.GetTypes()) {
					if (type.IsSubclassOf(typeof(ResourceConverter))) {
						var converter = (ResourceConverter)Activator.CreateInstance(type);
						foreach (var f in converter.GetSupportedFormats()) {
							if (!converters.ContainsKey(f))
								converters.Add(f, new List<ResourceConverter> { converter });
							else converters[f].Add(converter);
						}
					}
				}
			}
		}

		public int ChangeDirectory(string[] dir) {
			CurrentDirectory = dir;
			cd = new DirectoryInfo(_rootPath + "/charts/" + string.Join("/", dir));
			items = cd.GetDirectories();
			return items.Length;
		}

		public int OpenDirectory(int id) {
			string[] nd = new string[CurrentDirectory.Length + 1];
			Array.Copy(CurrentDirectory, nd, CurrentDirectory.Length);
			nd[CurrentDirectory.Length] = items[id].Name;
			return ChangeDirectory(nd);
		}

		public int ReturnToDirectory(int id) {
			string[] nd = new string[id + 1];
			Array.Copy(CurrentDirectory, nd, id + 1);
			return ChangeDirectory(nd);
		}

		public ResourceItemMeta GetItemMeta(int id) {
			var item = items[id];
			AsyncDelivery<Texture2D> cover = null;
			var coverFile = item.GetFiles("cover.*");
			if (coverFile.Length > 0) {
				cover = new AsyncDelivery<Texture2D>();
				var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
				cover.CancelSource = task.Cancel;
				Game.NetworkTaskWorker.SubmitNetworkTask(task);
			}
			string name = item.Name;
			string desc = "(Unknown)";
			var metaFile = new FileInfo(item.FullName + "/meta.json");
			if (metaFile.Exists) {
				using (var reader = new StreamReader(metaFile.FullName)) {
					var meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
					name = meta.song.name;
					desc = meta.chart.name;
				}
			}
			return new ResourceItemMeta {
				IsDirectory = false,
				Icon = cover,
				Name = name,
				DescriptionMain = desc,
			};
		}

		public ChartDetail GetItemDetail(int id) {
			var item = items[id];
			AsyncDelivery<Texture2D> cover = null;
			var coverFile = item.GetFiles("cover.*");
			if (coverFile.Length > 0) {
				cover = new AsyncDelivery<Texture2D>();
				var task = new LoadTextureTask(Game.FileProtocolPrefix + coverFile[0].FullName, cover.Deliver);
				cover.CancelSource = task.Cancel;
				Game.NetworkTaskWorker.SubmitNetworkTask(task);
			}
			ChartMeta meta = new ChartMeta();
			var metaFile = new FileInfo(item.FullName + "/meta.json");
			if (metaFile.Exists) {
				using (var reader = new StreamReader(metaFile.FullName)) {
					meta = JsonConvert.DeserializeObject<ChartMeta>(reader.ReadToEnd());
				}
			}
			return new ChartDetail {
				Cover = cover,
				Meta = meta,
			};
		}

		public string GetItemPath(int id) {
			return items[id].Name + "/.umgc";
		}

		public bool ImportItemFrom(string path) {
			var file = new FileInfo(path);
			if (!converters.ContainsKey(file.Extension)) return false;
			foreach (var converter in converters[file.Extension]) {
				IEnumerable<Resource> resources = null;
				try {
					resources = converter.ConvertFrom(file);
				}
				catch (Exception ex) {
					Popup.Create(ex.Message);
					return false;
				}
				foreach (var res in resources) {
					if (!res.Valid) {
						Logger.Log("main", 3, "Resource", "Attempt to import invalid resource {0}", res);
					}
					else if (res is ChartResource) {
						var tres = (ChartResource)res;
						var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
						if (!dir.Exists) dir.Create();
						using (var writer = new StreamWriter(dir.FullName + "/.umgc")) {
							writer.Write(JsonConvert.SerializeObject(tres.Main, Game.GlobalJsonSerializerSettings));
						}
						using (var writer = new StreamWriter(dir.FullName + "/meta.json")) {
							writer.Write(JsonConvert.SerializeObject(tres.Meta, Game.GlobalJsonSerializerSettings));
						}
					}
					else if (res is CoverResource) {
						var tres = (CoverResource)res;
						var dir = new DirectoryInfo(_rootPath + "/charts/" + res.Name);
						if (!dir.Exists) dir.Create();
						var dest = new FileInfo(_rootPath + "/charts/" + res.Name + "/cover" + tres.Source.Extension);
						if (!dest.Exists) tres.Source.CopyTo(dest.FullName);

					}
					else if (res is SongResource) {
						var tres = (SongResource)res;
						var dir = new DirectoryInfo(_rootPath + "/songs/" + res.Name);
						if (!dir.Exists) dir.Create();
						var dest = new FileInfo(_rootPath + "/songs/" + res.Name + "/.ogg");
						if (!dest.Exists) tres.Source.CopyTo(dest.FullName);
					}
				}
				return true;
			}
			return false;
		}

		public string[] GetSupportedFormats() {
			return converters.Keys.ToArray();
		}
	}
}