using MainShell.Filewritable;
using System;
using System.IO;
using System.Linq;

namespace MainShell.Recipe.Models
{
    public class RecipeManager
    {
        public event EventHandler RecipesChanged;

        // 记录上次加载的基板配方名（放在根目录）
        private string LastLoadedFile => Path.Combine(Paths.RecipeBasePath, "last_loaded.txt");

        public CarrierRecipe CurrentCarrierRecipe { get; private set; }
        public SubstrateRecipe CurrentSubstrateRecipe { get; private set; }
        public WaferRecipe CurrentWaferRecipe { get; private set; }
        public ProcessRecipe CurrentProcessRecipe { get; private set; }

        public RecipeManager()
        {
            var lastLoaded = LoadLastLoadedRecipe();
            if (!string.IsNullOrWhiteSpace(lastLoaded))
            {
                // 构造阶段不主动抛事件，避免初始化期无意义通知
                SwitchSubstrateRecipeInternal(lastLoaded, cascade: true, notify: false);
            }
        }

        public void SaveLastLoadedRecipe(string recipeName)
        {
            var dir = Path.GetDirectoryName(LastLoadedFile);
            if (!string.IsNullOrWhiteSpace(dir) && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            File.WriteAllText(LastLoadedFile, recipeName ?? string.Empty);
        }

        public string LoadLastLoadedRecipe()
        {
            if (!File.Exists(LastLoadedFile))
                return string.Empty;

            return File.ReadAllText(LastLoadedFile).Trim();
        }

        public void SwitchCarrierRecipe(string carrierRecipeName)
        {
            SwitchCarrierRecipeInternal(carrierRecipeName, notify: true);
        }

        public void SwitchSubstrateRecipe(string substrateRecipeName)
        {
            // 需求：切换基板时自动切换芯片；切换芯片时自动切换工艺
            SwitchSubstrateRecipeInternal(substrateRecipeName, cascade: true, notify: true);
        }

        public void SwitchWaferRecipe(string waferRecipeName)
        {
            // 需求：切换芯片时自动切换工艺
            SwitchWaferRecipeInternal(waferRecipeName, cascade: true, notify: true);
        }

        public void SwitchProcessRecipe(string processRecipeName)
        {
            SwitchProcessRecipeInternal(processRecipeName, notify: true);
        }

        private void SwitchCarrierRecipeInternal(string carrierRecipeName, bool notify)
        {
            if (string.IsNullOrWhiteSpace(carrierRecipeName))
                return;

            CurrentCarrierRecipe = CurrentCarrierRecipe ?? new CarrierRecipe();
            CurrentCarrierRecipe.RecipeName = carrierRecipeName;

            var path = Path.Combine(Paths.CarrierRecipe, carrierRecipeName, CurrentCarrierRecipe.FileName);
            CurrentCarrierRecipe.Read(path);

            var substrateName = GetFirstSubstrateName(CurrentCarrierRecipe);
            if (!string.IsNullOrWhiteSpace(substrateName))
            {
                // 向下级联，但由最外层统一通知
                SwitchSubstrateRecipeInternal(substrateName, cascade: true, notify: false);
            }
            else
            {
                ClearSubstrateRecipeInternal(false);
            }

            if (notify)
                RaiseRecipesChanged();
        }

        private void SwitchSubstrateRecipeInternal(string substrateRecipeName, bool cascade, bool notify)
        {
            if (string.IsNullOrWhiteSpace(substrateRecipeName))
                return;

            CurrentSubstrateRecipe = CurrentSubstrateRecipe ?? new SubstrateRecipe();
            CurrentSubstrateRecipe.RecipeName = substrateRecipeName;

            var path = Path.Combine(Paths.SubstrateRecipe, substrateRecipeName, CurrentSubstrateRecipe.FileName);
            CurrentSubstrateRecipe.Read(path);

            SaveLastLoadedRecipe(substrateRecipeName);

            if (cascade)
            {
                var waferName = GetFirstWaferName(CurrentSubstrateRecipe);
                if (!string.IsNullOrWhiteSpace(waferName))
                {
                    SwitchWaferRecipeInternal(waferName, cascade: true, notify: false);
                }
                else
                {
                    // 没有关联芯片时，清空下游当前引用，避免残留旧状态
                    CurrentWaferRecipe = null;
                    CurrentProcessRecipe = null;
                }
            }

            if (notify)
                RaiseRecipesChanged();
        }

        private void SwitchWaferRecipeInternal(string waferRecipeName, bool cascade, bool notify)
        {
            if (string.IsNullOrWhiteSpace(waferRecipeName))
                return;

            CurrentWaferRecipe = CurrentWaferRecipe ?? new WaferRecipe();
            CurrentWaferRecipe.RecipeName = waferRecipeName;

            var path = Path.Combine(Paths.WaferRecipe, waferRecipeName, CurrentWaferRecipe.FileName);
            CurrentWaferRecipe.Read(path);

            if (cascade)
            {
                var processName = CurrentWaferRecipe.ProcessRecipeName;
                if (!string.IsNullOrWhiteSpace(processName))
                {
                    SwitchProcessRecipeInternal(processName, notify: false);
                }
                else
                {
                    CurrentProcessRecipe = null;
                }
            }

            if (notify)
                RaiseRecipesChanged();
        }

        private void SwitchProcessRecipeInternal(string processRecipeName, bool notify)
        {
            if (string.IsNullOrWhiteSpace(processRecipeName))
                return;

            CurrentProcessRecipe = CurrentProcessRecipe ?? new ProcessRecipe();
            CurrentProcessRecipe.RecipeName = processRecipeName;

            var path = Path.Combine(Paths.ProcessRecipe, processRecipeName, CurrentProcessRecipe.FileName);
            CurrentProcessRecipe.Read(path);

            if (notify)
                RaiseRecipesChanged();
        }

        private static string GetFirstSubstrateName(CarrierRecipe carrierRecipe)
        {
            if (carrierRecipe == null ||
                carrierRecipe.SubstrateSelectInfos == null ||
                carrierRecipe.SubstrateSelectInfos.Count == 0)
            {
                return string.Empty;
            }

            return carrierRecipe.SubstrateSelectInfos[0].SubstrateName;
        }

        private static string GetFirstWaferName(SubstrateRecipe substrateRecipe)
        {
            if (substrateRecipe == null ||
                substrateRecipe.WaferSelectInfos == null ||
                substrateRecipe.WaferSelectInfos.Count == 0)
            {
                return string.Empty;
            }

            var inUse = substrateRecipe.WaferSelectInfos
                .FirstOrDefault(x => x != null && x.IsUse && !string.IsNullOrWhiteSpace(x.WaferRecipeName));
            if (inUse != null)
                return inUse.WaferRecipeName;

            var firstValid = substrateRecipe.WaferSelectInfos
                .FirstOrDefault(x => x != null && !string.IsNullOrWhiteSpace(x.WaferRecipeName));
            return firstValid != null ? firstValid.WaferRecipeName : string.Empty;
        }

        private void RaiseRecipesChanged()
        {
            RecipesChanged?.Invoke(this, EventArgs.Empty);
        }

        public void DeleteCarrierRecipe(string recipeName)
        {
            DeleteRecipeFolder(Paths.CarrierRecipe, recipeName, out _);
        }

        public bool DeleteCarrierRecipe(string recipeName, out string error)
        {
            return DeleteRecipeFolder(Paths.CarrierRecipe, recipeName, out error);
        }

        public void DeleteSubstrateRecipe(string recipeName)
        {
            DeleteRecipeFolder(Paths.SubstrateRecipe, recipeName, out _);
        }

        public bool DeleteSubstrateRecipe(string recipeName, out string error)
        {
            return DeleteRecipeFolder(Paths.SubstrateRecipe, recipeName, out error);
        }

        public void DeleteWaferRecipe(string recipeName)
        {
            DeleteRecipeFolder(Paths.WaferRecipe, recipeName, out _);
        }

        public bool DeleteWaferRecipe(string recipeName, out string error)
        {
            return DeleteRecipeFolder(Paths.WaferRecipe, recipeName, out error);
        }

        public void DeleteProcessRecipe(string recipeName)
        {
            DeleteRecipeFolder(Paths.ProcessRecipe, recipeName, out _);
        }

        public bool DeleteProcessRecipe(string recipeName, out string error)
        {
            return DeleteRecipeFolder(Paths.ProcessRecipe, recipeName, out error);
        }

        public bool DeleteRecipeFolder(string baseFolder, string recipeName, out string error)
        {
            error = null;
            if (string.IsNullOrWhiteSpace(baseFolder) || string.IsNullOrWhiteSpace(recipeName))
            {
                error = "配方名称不能为空";
                return false;
            }

            var path = Path.Combine(baseFolder, recipeName);
            if (!Directory.Exists(path))
            {
                error = "配方目录不存在";
                return false;
            }

            try
            {
                Directory.Delete(path, true);
                return true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
                return false;
            }
        }

        public bool CopyRecipeFolder(string baseFolder, string sourceRecipeName, string targetRecipeName, out string error)
        {
            error = null;
            if (string.IsNullOrWhiteSpace(baseFolder) || string.IsNullOrWhiteSpace(sourceRecipeName) || string.IsNullOrWhiteSpace(targetRecipeName))
            {
                error = "配方名称不能为空";
                return false;
            }

            if (sourceRecipeName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
                targetRecipeName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
            {
                error = "名称包含非法字符";
                return false;
            }

            var sourcePath = Path.Combine(baseFolder, sourceRecipeName);
            var targetPath = Path.Combine(baseFolder, targetRecipeName);

            if (!Directory.Exists(sourcePath))
            {
                error = "源文件夹不存在";
                return false;
            }

            if (Directory.Exists(targetPath))
            {
                error = "目标文件夹已存在";
                return false;
            }

            try
            {
                CopyDirectory(sourcePath, targetPath);
                return true;
            }
            catch (Exception ex)
            {
                error = ex.Message;

                try
                {
                    if (Directory.Exists(targetPath))
                    {
                        Directory.Delete(targetPath, true);
                    }
                }
                catch
                {
                }

                return false;
            }
        }

        public void ClearCarrierRecipe()
        {
            ClearCarrierRecipeInternal(true);
        }

        public void ClearSubstrateRecipe()
        {
            ClearSubstrateRecipeInternal(true);
        }

        public void ClearWaferRecipe()
        {
            ClearWaferRecipeInternal(true);
        }

        public void ClearProcessRecipe()
        {
            ClearProcessRecipeInternal(true);
        }

        private void ClearCarrierRecipeInternal(bool notify)
        {
            CurrentCarrierRecipe = null;

            if (notify)
                RaiseRecipesChanged();
        }

        private void ClearSubstrateRecipeInternal(bool notify)
        {
            CurrentSubstrateRecipe = null;
            CurrentWaferRecipe = null;
            CurrentProcessRecipe = null;
            SaveLastLoadedRecipe(string.Empty);

            if (notify)
                RaiseRecipesChanged();
        }

        private void ClearWaferRecipeInternal(bool notify)
        {
            CurrentWaferRecipe = null;
            CurrentProcessRecipe = null;

            if (notify)
                RaiseRecipesChanged();
        }

        private void ClearProcessRecipeInternal(bool notify)
        {
            CurrentProcessRecipe = null;

            if (notify)
                RaiseRecipesChanged();
        }

        private static void CopyDirectory(string sourcePath, string targetPath)
        {
            Directory.CreateDirectory(targetPath);

            foreach (var filePath in Directory.GetFiles(sourcePath))
            {
                var fileName = Path.GetFileName(filePath);
                var targetFilePath = Path.Combine(targetPath, fileName);
                File.Copy(filePath, targetFilePath, false);
            }

            foreach (var directoryPath in Directory.GetDirectories(sourcePath))
            {
                var directoryName = Path.GetFileName(directoryPath);
                var targetDirectoryPath = Path.Combine(targetPath, directoryName);
                CopyDirectory(directoryPath, targetDirectoryPath);
            }
        }

        public bool RenameFolder(string baseFolder, string oldName, string newName, out string error)
        {
            error = null;
            if (string.IsNullOrWhiteSpace(oldName) || string.IsNullOrWhiteSpace(newName))
            {
                error = "名称不能为空";
                return false;
            }

            if (oldName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
                newName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
            {
                error = "名称包含非法字符";
                return false;
            }

            var src = Path.Combine(baseFolder, oldName);
            var dst = Path.Combine(baseFolder, newName);

            if (!Directory.Exists(src))
            {
                error = "源文件夹不存在";
                return false;
            }

            if (Directory.Exists(dst))
            {
                error = "目标文件夹已存在";
                return false;
            }

            try
            {
                if (string.Equals(oldName, newName, StringComparison.OrdinalIgnoreCase) &&
                    !string.Equals(oldName, newName, StringComparison.Ordinal))
                {
                    var temp = Path.Combine(baseFolder, oldName + "_tmp_" + Guid.NewGuid().ToString("N"));
                    Directory.Move(src, temp);
                    Directory.Move(temp, dst);
                }
                else
                {
                    Directory.Move(src, dst);
                }

                return true;
            }
            catch (Exception ex)
            {
                error = ex.Message;
                return false;
            }
        }
    }
}
