using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using ZionVault.Binder.Verified;

namespace ZionVault.Util
{
    public class Naming
    {
        public static string GeneratePath(string rule, string inputFileFullPath = @"", List<Field> fields = null)
        {
            return GetBaseName(rule, inputFileFullPath, fields);
        }

        public static string GenerateFileName(string rule, string inputFileFullPath, string outputPath, string outputFileExtension, List<Field> fields, bool merge = true)
        {
            return FileNameCount(outputPath, GetBaseName(rule, inputFileFullPath, fields), outputFileExtension, merge);
        }

        private static List<string> BuildOptions(string rule)
        {
            List<string> mult = new List<string>();

            string pattern = @"\(\{[\w\d]{0,}\}\|\{[\w\d]{0,}\}\)";

            foreach (Match match in Regex.Matches(rule, pattern))
            {
                mult.Add(match.Value);
            }

            List<string> options = new List<string>();

            string[] parts = Regex.Split(rule, pattern);
            int index = 0;
            foreach (string part in parts)
            {
                foreach (Match match in Regex.Matches(part, @"\{[\w\d\s]{0,}\}"))
                {
                    options.Add(match.Value);
                }
                if (index < mult.Count)
                    options.Add(mult[index]);
                index++;
            }

            return options;
        }

        private static string MakeValidFileName(string name)
        {
            string invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
            string invalidRegStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);

            return System.Text.RegularExpressions.Regex.Replace(name, invalidRegStr, "_");
        }

        private static string GetPartial(string option, string inputFileFullPath)
        {
            switch (option)
            {
                case "{Nome do arquivo}":
                    return inputFileFullPath != @"" ? Path.GetFileNameWithoutExtension(inputFileFullPath) : option;
                case "{Data atual}":
                    return DateTime.Now.ToString(@"dd/MM/yyyy");
                case "{Dia}":
                    return DateTime.Now.ToString(@"dd");
                case "{Mês}":
                    return DateTime.Now.ToString(@"MM");
                case "{Ano}":
                    return DateTime.Now.ToString(@"yyyy");
                case "{Hora atual}":
                    return DateTime.Now.ToString(@"HH:mm:ss");
                case "{Horas}":
                    return DateTime.Now.ToString(@"HH");
                case "{Minutos}":
                    return DateTime.Now.ToString(@"mm");
                case "{Segundos}":
                    return DateTime.Now.ToString(@"ss");
                case "{Diretório de origem do arquivo}":
                    return inputFileFullPath != @"" ? Directory.GetParent(inputFileFullPath).Name : option;
            }

            return null;
        }

        private static string GetField(string option, List<Field> fields)
        {
            string name = string.Empty;
            string[] field_name = option.Trim('(').Trim(')').Split('|');
            if (field_name.Length > 1)
            {
                foreach (string f in field_name)
                {
                    name = (from Field field in fields
                            where "{" + field.Name + "}" == f && field.Value.Trim() != string.Empty
                            orderby field.Quality descending
                            select field.Value).First();
                    if (name != string.Empty)
                        break;
                }
            }
            else
            {
                string value = fields?.Where(field => field.Name.Contains(option.Trim('{').Trim('}')) == true).Select(f => f.Value).FirstOrDefault();

                if (value != string.Empty && value != null)
                    return value;
            }
            return name != string.Empty ? name : null;
        }

        private static string GetBaseName(string rule, string inputFileFullPath, List<Field> fields)
        {
            List<string> options = BuildOptions(rule);

            //string name = string.Empty;
            string name = rule;

            foreach (string option in options)
            {
                string add = string.Empty;
                add = GetPartial(option, inputFileFullPath);
                if (add == null)
                {
                    add = GetField(option, fields);
                }
                //name += add;
                if (add != null)
                    name = name.Replace(option, add);
            }

            if (options.Count == 1 && name == string.Empty && !Regex.IsMatch(rule, @"[\{\}\|\(\)]"))
            {
                return rule;
            }
            else
            {
                return name;
                //return MakeValidFileName(name);
            }
        }

        private static string FileNameCount(string outputPath, string fileName, string extension, bool merge)
        {
            int index = 1;
            string tempValue = fileName;

            while (System.IO.File.Exists(string.Format(@"{0}\{1}{2}", outputPath, tempValue, extension)) && merge == false)
            {
                tempValue = string.Format(@"{0} ({1})", fileName, index);
                index++;
            }

            return tempValue + extension;
        }
    }
}
