using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using AxCopilot.Handlers;
using AxCopilot.Models;
using AxCopilot.SDK;
using AxCopilot.Services;

namespace AxCopilot.Core;

public class PluginHost
{
	private readonly SettingsService _settings;

	private readonly CommandResolver _resolver;

	private readonly List<IActionHandler> _loadedPlugins = new List<IActionHandler>();

	public IReadOnlyList<IActionHandler> LoadedPlugins => _loadedPlugins;

	public PluginHost(SettingsService settings, CommandResolver resolver)
	{
		_settings = settings;
		_resolver = resolver;
	}

	public void LoadAll()
	{
		_loadedPlugins.Clear();
		foreach (PluginEntry item in _settings.Settings.Plugins.Where((PluginEntry p) => p.Enabled))
		{
			LoadPlugin(item.Path);
		}
		string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "skills");
		if (!Directory.Exists(path))
		{
			return;
		}
		foreach (string item2 in Directory.EnumerateFiles(path, "*.skill.json"))
		{
			LoadJsonSkill(item2);
		}
	}

	private void LoadPlugin(string dllPath)
	{
		if (!File.Exists(dllPath))
		{
			LogService.Warn("플러그인 파일 없음: " + dllPath);
			return;
		}
		try
		{
			Assembly assembly = Assembly.LoadFrom(dllPath);
			IEnumerable<Type> enumerable = from t in assembly.GetExportedTypes()
				where typeof(IActionHandler).IsAssignableFrom(t) && !t.IsAbstract
				select t;
			foreach (Type item in enumerable)
			{
				if (Activator.CreateInstance(item) is IActionHandler actionHandler)
				{
					_resolver.RegisterHandler(actionHandler);
					_loadedPlugins.Add(actionHandler);
					LogService.Info("플러그인 로드: " + actionHandler.Metadata.Name + " v" + actionHandler.Metadata.Version);
				}
			}
		}
		catch (Exception ex)
		{
			LogService.Error("플러그인 로드 실패 (" + dllPath + "): " + ex.Message);
		}
	}

	private void LoadJsonSkill(string skillPath)
	{
		try
		{
			IActionHandler actionHandler = JsonSkillLoader.Load(skillPath);
			if (actionHandler != null)
			{
				_resolver.RegisterHandler(actionHandler);
				_loadedPlugins.Add(actionHandler);
				LogService.Info("JSON 스킬 로드: " + actionHandler.Metadata.Name);
			}
		}
		catch (Exception ex)
		{
			LogService.Error("JSON 스킬 로드 실패 (" + skillPath + "): " + ex.Message);
		}
	}

	public void Reload()
	{
		LogService.Info("플러그인 전체 재로드 시작");
		LoadAll();
	}

	public int InstallFromZip(string zipPath)
	{
		if (!File.Exists(zipPath))
		{
			LogService.Warn("플러그인 zip 파일 없음: " + zipPath);
			return 0;
		}
		string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "plugins");
		Directory.CreateDirectory(text);
		int num = 0;
		try
		{
			using ZipArchive zipArchive = ZipFile.OpenRead(zipPath);
			string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(zipPath);
			string text2 = Path.Combine(text, fileNameWithoutExtension);
			Directory.CreateDirectory(text2);
			foreach (ZipArchiveEntry entry in zipArchive.Entries)
			{
				if (!string.IsNullOrEmpty(entry.Name))
				{
					string text3 = Path.Combine(text2, entry.Name);
					if (!Path.GetFullPath(text3).StartsWith(Path.GetFullPath(text2)))
					{
						LogService.Warn("플러그인 zip 경로 위험: " + entry.FullName);
					}
					else
					{
						entry.ExtractToFile(text3, overwrite: true);
					}
				}
			}
			foreach (string dllFile in Directory.EnumerateFiles(text2, "*.dll"))
			{
				if (!_settings.Settings.Plugins.Any((PluginEntry p) => p.Path == dllFile))
				{
					_settings.Settings.Plugins.Add(new PluginEntry
					{
						Enabled = true,
						Path = dllFile
					});
					LoadPlugin(dllFile);
					num++;
				}
			}
			string text4 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "skills");
			Directory.CreateDirectory(text4);
			foreach (string item in Directory.EnumerateFiles(text2, "*.skill.json"))
			{
				string text5 = Path.Combine(text4, Path.GetFileName(item));
				File.Copy(item, text5, overwrite: true);
				LoadJsonSkill(text5);
				num++;
			}
			if (num > 0)
			{
				_settings.Save();
			}
			LogService.Info($"플러그인 설치 완료: {zipPath} → {num}개 핸들러");
		}
		catch (Exception ex)
		{
			LogService.Error("플러그인 zip 설치 실패: " + ex.Message);
		}
		return num;
	}

	public bool UninstallPlugin(string dllPath)
	{
		try
		{
			PluginEntry pluginEntry = _settings.Settings.Plugins.FirstOrDefault((PluginEntry p) => p.Path == dllPath);
			if (pluginEntry != null)
			{
				_settings.Settings.Plugins.Remove(pluginEntry);
				_settings.Save();
			}
			string directoryName = Path.GetDirectoryName(dllPath);
			if (directoryName != null && Directory.Exists(directoryName))
			{
				string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "plugins");
				if (Path.GetFullPath(directoryName).StartsWith(Path.GetFullPath(path)))
				{
					Directory.Delete(directoryName, recursive: true);
				}
			}
			LogService.Info("플러그인 제거 완료: " + dllPath);
			return true;
		}
		catch (Exception ex)
		{
			LogService.Error("플러그인 제거 실패: " + ex.Message);
			return false;
		}
	}
}
