using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Tool.ReadChecker
{
    public class ReadModuleChecker
    {
        private readonly string moduleArtRootPath;
        private readonly string moduleSrcRootPath;
        private readonly ReadLog log;
        private readonly ModuleRule rule;
        private string curModuleId;
        public string CurModuleId {
            get { return curModuleId; }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    curModuleId = value;
                    log.CurModuleId = value;
                }
            } 
        }
        public string CurId => Regex.Match(CurModuleId, @"(\d+)").Value;
        public ReadLog Logger => log;
        public ReadModuleChecker(ModuleRule rule)
        {
            this.rule = rule;
            moduleArtRootPath = string.IsNullOrEmpty(rule.artRootPath) ? null : Path.Combine(Application.dataPath, rule.artRootPath);
            moduleSrcRootPath = string.IsNullOrEmpty(rule.srcRootPath) ? null : Path.Combine(Application.dataPath, rule.srcRootPath);
            log = new ReadLog(Path.GetFileNameWithoutExtension(moduleArtRootPath));
        }
        public string CheckModelByRule()
        {
            if (rule == null)
            {
                throw new Exception("CheckModelByRule rule is null");
            }
            log.Log("====CheckModulesBegin====");
            List<string> idList = GetSingleModelIds();
            foreach (var id in idList)
            {
                CheckSingleModuleByRule(id);
            }
            log.Log("====CheckModulesEnd====");
            return log.SaveToJson();
        }

        public void CheckSingleModuleByRule(string id)
        {
            CurModuleId = id;
            log.Log("----CheckSingleModuleByRuleBegin----");
            CheckSingleModuleArtByRule(id);
            CheckSingleModuleSrcByRule(id);
            log.Log("----CheckSingleModuleByRuleEnd----");
            CurModuleId = null;
        }

        private void CheckSingleModuleSrcByRule(string id)
        {
            if (moduleSrcRootPath != null)
            {
                var modulePath = Path.Combine(moduleSrcRootPath, id);
                var ruleList = rule.SrcRequireList;
                foreach (var rule in ruleList)
                {
                    var subPath = Path.Combine(modulePath, rule.path);
                    CheckFolderByRule(subPath, rule);
                }
            }
        }
        private void CheckSingleModuleArtByRule(string id)
        {
            var modulePath = Path.Combine(moduleArtRootPath, id);
            var ruleList = rule.ArtRequireList;
            foreach (var rule in ruleList)
            {
                var subPath = Path.Combine(modulePath, rule.path);
                CheckFolderByRule(subPath, rule);
            }
        }

        private bool IsDirectoryEmpty(string path)
        {
            return !Directory.EnumerateFileSystemEntries(path).Any();
        }
        private void CheckFolderByRule(string subPath, RequireRule rule)
        {
            if (Directory.Exists(subPath))
            {
                if(IsDirectoryEmpty(subPath))
                {
                    log.AddFolderMissingError(subPath);
                    return;
                }

                if (rule.Strict && rule.allowedFolderNamePatternSet != null && rule.allowedFolderNamePatternSet.Count > 0)
                {
                    string[] folders = Directory.GetDirectories(subPath);
                    foreach (string folder in folders)
                    {
                        string folderName = Path.GetFileName(folder);
                        if (!IsMatch(folderName, rule.allowedFolderNamePatternSet))
                        {
                            log.AddFolderNameWarning(folder);
                        }
                    }
                }
                //单个module根目录
                if (rule.path == "")
                {
                    string[] files = Directory.GetFiles(subPath);
                    foreach (var filePath in files)
                    {
                        CheckFile(filePath, rule);
                    }
                }
                else
                {
                    string[] files = Directory.GetFiles(subPath, "*.*", SearchOption.AllDirectories);
                    foreach (var filePath in files)
                    {
                        CheckFile(filePath, rule);
                    }
                }
            }
            else
            {
                log.AddFolderMissingError(subPath);
                return;
            }
            rule.extraCheck?.Invoke(subPath, this);
        }

        private void CheckFile(string filePath, RequireRule rule)
        {
            var extension = Path.GetExtension(filePath);
            if (extension == ".meta")
            {
                return;
            }

            if (rule.allowedExtensionSet != null && !rule.allowedExtensionSet.Contains(extension))
            {
                log.AddFileTypeWarning(filePath);
                return;
            }

            if (rule.Strict && rule.allowedFileNamePatternSet != null && rule.allowedFileNamePatternSet.Count > 0)
            {
                var fileName = Path.GetFileNameWithoutExtension(filePath);
                if (!IsMatch(fileName, rule.allowedFileNamePatternSet))
                {
                    log.AddFileNameWarning(filePath);
                    return;
                }
            }

            //switch (extension)
            //{
            //    case ".ogg":
            //        break;
            //    default:
            //        Console.WriteLine("Invalid extension");
            //        break;
            //}
        }
        private bool IsMatch(string path, HashSet<string> patternSet)
        {
            foreach (var pattern in patternSet)
            {
                Regex regex = new(pattern);
                bool isMatch = regex.IsMatch(path);
                if (isMatch)
                {
                    return true;
                }
            }
            return false;
        }

        private List<string> GetSingleModelIds()
        {
            List<string> moduleIdList = new();

            string[] moduleIds = Directory.GetDirectories(moduleArtRootPath).Where(d => Directory.EnumerateFileSystemEntries(d).Any()).Select(d => Path.GetFileName(d)).ToArray();
            foreach (string moduleId in moduleIds)
            {
                Regex regex = new(rule.artNamePattern);
                bool isMatch = regex.IsMatch(moduleId);
                if (isMatch)
                {
                    moduleIdList.Add(moduleId);
                }
            }
            return moduleIdList;
        }
        public void CheckFilesExists(List<string> files)
        {
            foreach (var file in files)
            {
                if (!File.Exists(file))
                {
                    Logger.AddFileMissingError(file);
                }
            }
        }

        public void CheckFileExists(string file)
        {
            if (!File.Exists(file))
            {
                Logger.AddFileMissingError(file);
            }
        }

        public void CheckFoldersExists(List<string> folders)
        {
            foreach (var folder in folders)
            {
                if (!Directory.Exists(folder))
                {
                    Logger.AddFolderMissingError(folder);
                }
            }
        }

    }
}

