using Microsoft.Extensions.Logging;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;

namespace File_Folder_Helper.Helpers;

internal static partial class HelperCreateNoteFiles
{

    [GeneratedRegex("[^a-z0-9-]")]
    private static partial Regex AlphaNumOnly();

    private static string? GetTags(string tagsText)
    {
        string? result;
        StringBuilder stringBuilder = new();
        if (string.IsNullOrEmpty(tagsText))
            result = null;
        else
        {
            string[] segments;
            _ = stringBuilder.AppendLine("tags:");
            string[] tags = tagsText.Split(';', StringSplitOptions.RemoveEmptyEntries);
            foreach (string tag in tags)
            {
                segments = tag.Split(':');
                _ = stringBuilder.AppendLine($"- '{segments.First()}'");
            }
            result = stringBuilder.ToString().Trim();
        }
        return result;
    }

    private static string? GetLinks(string type, string linksText)
    {
        string? result;
        StringBuilder stringBuilder = new();
        if (!string.IsNullOrEmpty(linksText))
            result = null;
        else
        {
            string linkLower;
            string[] segments;
            string[] links = linksText.Split(';', StringSplitOptions.RemoveEmptyEntries);
            foreach (string link in links)
            {
                segments = link.Split(':');
                linkLower = AlphaNumOnly().Replace(segments.First().Trim().ToLower(), "-").Replace("--", "-");
                if (segments.Length == 1)
                    _ = stringBuilder.AppendLine($"- [[{type}/{linkLower}]]");
                else if (segments.Length == 2)
                    _ = stringBuilder.AppendLine($"- [{type}/{linkLower}]({segments.Last()})");
                else
                    continue;
            }
            result = stringBuilder.ToString().Trim();
        }
        return result;
    }

    private static string? GetAttributes(string[] columns, string[]? headerColumns, int expectedCount)
    {
        string? result;
        if (headerColumns is null || columns.Length <= expectedCount)
            result = null;
        else
        {
            StringBuilder stringBuilder = new();
            for (int j = expectedCount; j < columns.Length; j++)
            {
                if (headerColumns.Length <= j)
                    continue;
                _ = stringBuilder.AppendLine($"{headerColumns[j].Trim()}: '{columns[j].Trim()}'");
            }
            result = stringBuilder.ToString().Trim();
        }
        return result;
    }

    private static void CleanExistingFiles(ILogger<Worker> logger, string directory, long ticks)
    {
        string check;
        string[] lines;
        string checkFile;
        string? fileDirectory;
        string checkDirectory;
        bool circularReference;
        string fileNameWithoutExtension;
        char altDrive = directory[0] is 'c' or 'C' ? 'D' : 'C';
        string[] files = Directory.GetFiles(directory, "*.md", SearchOption.AllDirectories);
        string match = ",*** *** *** *** *** *** *** *** ***,*** *** *** *** *** *** *** *** ***,*** *** *** *** *** *** *** *** ***,,TODO:,*** *** *** *** *** *** *** *** ***,*** *** *** *** *** *** *** *** ***,,Notes:,*** *** *** *** *** *** *** *** ***,*** *** *** *** *** *** *** *** ***";
        foreach (string file in files)
        {
            lines = File.ReadAllLines(file);
            if (lines.Length < 1)
                continue;
            circularReference = false;
            fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
            for (int i = 0; i < lines.Length; i++)
            {
                if (!lines[i].Contains($"[[{fileNameWithoutExtension}]]"))
                    continue;
                lines[i] = lines[i].Replace("[[", "__").Replace("]]", "__");
                if (!circularReference)
                    circularReference = true;
            }
            if (circularReference)
                File.WriteAllLines(file, lines);
            lines[0] = string.Empty;
            check = string.Join(',', lines);
            if (check != match)
                continue;
            fileDirectory = Path.GetDirectoryName(file);
            if (string.IsNullOrEmpty(fileDirectory))
                continue;
            checkDirectory = $"{altDrive}:/{ticks}/{fileDirectory[3..]}";
            if (!Directory.Exists(checkDirectory))
                _ = Directory.CreateDirectory(checkDirectory);
            checkFile = $"{altDrive}:/{ticks}/{file[3..]}";
            if (File.Exists(checkFile))
                continue;
            File.Move(file, checkFile);
        }
        HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, directory);
    }

    private static void CreateDailyNotes(string argsZero, long ticks)
    {
        string file;
        string directory;
        string weekOfYear;
        DateTime dateTime;
        string lastDirectory = string.Empty;
        DateTime startDateTime = DateTime.Now.AddDays(1);
        Calendar calendar = new CultureInfo("en-US").Calendar;
        double totalDays = new TimeSpan(DateTime.Now.AddDays(1000).Ticks - startDateTime.Ticks).TotalDays;
        int days = (int)Math.Ceiling(totalDays);
        for (int i = 0; i < days; i++)
        {
            dateTime = startDateTime.AddDays(i);
            weekOfYear = calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00");
            directory = Path.Combine(argsZero, ticks.ToString(), dateTime.ToString("yyyy"), $"Week_{weekOfYear}");
            if (!Directory.Exists(directory))
                _ = Directory.CreateDirectory(directory);
            file = string.Concat(Path.Combine(directory, $"{dateTime:yyyy-MM-dd}.md"));
            if (File.Exists(file))
                continue;
            File.WriteAllLines(file,
            [
                "---",
                "type: daily-note",
                $"created: {dateTime:yyyy-MM-dd}",
                "---",
                string.Empty,
                $"# {dateTime:yyyy-MM-dd dddd}",
                string.Empty,
                "```bash",
                string.Empty,
                "```",
            ]);
            if (directory != lastDirectory)
            {
                Directory.SetCreationTime(directory, dateTime);
                Directory.SetLastWriteTime(directory, dateTime);
            }
            lastDirectory = directory;
        }
    }

    private static void CreateImportFiles(long ticks, List<string> importFiles)
    {
        bool csv;
        bool tsv;
        string file;
        string text;
        string type;
        string title;
        string? tags;
        string? links;
        string[] lines;
        int bodyKey = 5;
        int tagsKey = 3;
        int typeKey = 0;
        string fileName;
        string tagsText;
        int linksKey = 4;
        int titleKey = 1;
        string linksText;
        string[] columns;
        string? directory;
        string? attributes;
        int descriptionKey = 2;
        string[]? headerColumns;
        List<string> allLines = [];
        string destinationDirectory;
        DateTime dateTime = new(ticks);
        string csvHeader = "type,title,description,tags,links,body";
        string tsvHeader = "type\ttitle\tdescription\ttags\tlinks\tbody";
        int expectedCount = csvHeader.Length - csvHeader.Replace(",", string.Empty).Length + 1;
        foreach (string importFile in importFiles)
        {
            csv = false;
            tsv = false;
            headerColumns = null;
            directory = Path.GetDirectoryName(importFile);
            if (directory is null)
                continue;
            lines = File.ReadAllLines(importFile);
            for (int i = 0; i < lines.Length; i++)
            {
                if (i == 0)
                {
                    if (lines[i].StartsWith(csvHeader))
                    {
                        (csv, tsv) = (true, false);
                        headerColumns = lines[i].Split(',');
                    }
                    else if (lines[i].StartsWith(tsvHeader))
                    {
                        (csv, tsv) = (false, true);
                        headerColumns = lines[i].Split('\t');
                    }
                    else
                        break;
                    continue;
                }
                if (csv)
                    columns = lines[i].Split(',');
                else if (tsv)
                    columns = lines[i].Split('\t');
                else
                    continue;
                if (columns.Length < expectedCount)
                    continue;
                title = columns[titleKey].Trim();
                tagsText = columns[tagsKey].Trim();
                linksText = columns[linksKey].Trim();
                fileName = AlphaNumOnly().Replace(title.ToLower(), "-").Replace("--", "-");
                type = AlphaNumOnly().Replace(columns[typeKey].Trim().ToLower(), "-").Replace("--", "-");
                tags = GetTags(tagsText);
                links = GetLinks(type, linksText);
                attributes = GetAttributes(columns, headerColumns, expectedCount);
                destinationDirectory = Path.Combine(directory, type);
                if (!Directory.Exists(destinationDirectory))
                    _ = Directory.CreateDirectory(destinationDirectory);
                file = Path.Combine(destinationDirectory, $"{fileName}.md");
                allLines.Clear();
                allLines.Add("---");
                allLines.Add($"type: \"{type}\"");
                allLines.Add($"title: \"{title}\"");
                allLines.Add($"description: \"{columns[descriptionKey].Trim()}\"");
                allLines.Add($"created: \"{dateTime:yyyy-MM-ddTHH:mm:ss.fffZ}\"");
                allLines.Add($"updated: \"{dateTime:yyyy-MM-ddTHH:mm:ss.fffZ}\"");
                if (!string.IsNullOrEmpty(tags))
                    allLines.Add(tags);
                if (!string.IsNullOrEmpty(attributes))
                    allLines.Add(attributes);
                allLines.Add("---");
                allLines.Add(string.Empty);
                allLines.Add($"# {title}");
                allLines.Add(string.Empty);
                if (!string.IsNullOrEmpty(links))
                    allLines.Add(links);
                allLines.Add(string.Empty);
                allLines.Add($"## Comment {dateTime:yyyy-MM-dd}");
                allLines.Add(string.Empty);
                allLines.Add(columns[bodyKey].Trim());
                allLines.Add(string.Empty);
                text = string.Join(Environment.NewLine, allLines);
                File.WriteAllText(file, text);
            }
        }
    }

    internal static void CreateNoteFiles(ILogger<Worker> logger, string argsZero)
    {
        List<string> importFiles = [];
        long ticks = DateTime.Now.Ticks;
        CleanExistingFiles(logger, argsZero, ticks);
        importFiles.AddRange(Directory.GetFiles(argsZero, "*.csv", SearchOption.TopDirectoryOnly));
        importFiles.AddRange(Directory.GetFiles(argsZero, "*.tsv", SearchOption.TopDirectoryOnly));
        if (importFiles.Count == 0)
            CreateDailyNotes(argsZero, ticks);
        else
            CreateImportFiles(ticks, importFiles);
    }

}