using Microsoft.Extensions.Configuration;

namespace URLNotesGrabberCORE
{
    // Inverse of OutputMode. Recursively walks the PathInput tree (the same directory tree the
    // no-parameter run uses) and restores every *.bak back to its *.txt, first preserving the
    // current *.txt as the next-free *.bkN. Consumes the *.bak (File.Move). Filesystem-only;
    // does not read the DB. An optional blogname argument filters by path substring.
    public static class RevertMode
    {
        public static int Run(IConfiguration config, string? blogFilter = null)
        {
            string? root = config["appSettings:PathInput"];
            if (string.IsNullOrWhiteSpace(root) || !Directory.Exists(root))
            {
                Console.WriteLine($"PathInput is not set or does not exist: '{root}'. Nothing to revert.");
                return 0;
            }

            Console.WriteLine($"Searching for .bak files under: {root}");

            // Recursively collect every *.bak, optionally filtered by path substring (blogname).
            var bakFiles = EnumerateBakFiles(root)
                .Where(f => string.IsNullOrWhiteSpace(blogFilter)
                            || f.IndexOf(blogFilter, StringComparison.OrdinalIgnoreCase) >= 0)
                .ToList();

            if (bakFiles.Count == 0)
            {
                Console.WriteLine("No .bak files found. Nothing to revert.");
                return 0;
            }

            Console.Write($"WARNING: This will restore {bakFiles.Count} .bak file(s) over their .txt files. " +
                          $"Current .txt files are preserved as the next-free .bkN. Continue? (yes/no): ");
            string? response = Console.ReadLine();
            if (string.IsNullOrWhiteSpace(response) || !response.Equals("yes", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("Operation cancelled.");
                return 0;
            }

            int restored = 0, backedUp = 0;
            foreach (var bakFile in bakFiles)
            {
                try
                {
                    string txtPath = Path.ChangeExtension(bakFile, ".txt");

                    if (File.Exists(txtPath))
                    {
                        string bkPath = NextFreeBkPath(txtPath);
                        File.Move(txtPath, bkPath);
                        backedUp++;
                        Console.WriteLine($"  Backed up {Path.GetFileName(txtPath)} -> {Path.GetFileName(bkPath)}");
                    }

                    File.Move(bakFile, txtPath);
                    restored++;
                    Console.WriteLine($"  Restored {bakFile} -> {Path.GetFileName(txtPath)}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"  Error reverting {bakFile}: {ex.Message}");
                }
            }

            Console.WriteLine($"\nRevert mode complete. Restored {restored} file(s); backed up {backedUp} current .txt file(s).");
            return 0;
        }

        // Recursively yields every *.bak path under root. Per-directory try/catch so an
        // inaccessible folder doesn't abort the whole walk (mirrors TraverseDirectory).
        private static IEnumerable<string> EnumerateBakFiles(string path)
        {
            string[] subDirs;
            try { subDirs = Directory.GetDirectories(path); }
            catch (Exception ex)
            {
                Console.WriteLine($"  Skipping '{path}': {ex.Message}");
                yield break;
            }

            foreach (var dir in subDirs)
                foreach (var bak in EnumerateBakFiles(dir))
                    yield return bak;

            string[] bakFiles;
            try { bakFiles = Directory.GetFiles(path, "*.bak"); }
            catch (Exception ex)
            {
                Console.WriteLine($"  Skipping files in '{path}': {ex.Message}");
                yield break;
            }

            foreach (var bak in bakFiles)
                yield return bak;
        }

        // Returns the lowest unused .bkN path for a given .txt file (.bk1, .bk2, ...).
        private static string NextFreeBkPath(string txtFile)
        {
            for (int n = 1; ; n++)
            {
                string candidate = Path.ChangeExtension(txtFile, $".bk{n}");
                if (!File.Exists(candidate)) return candidate;
            }
        }
    }
}
