﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

namespace GuidRandomiser
{
    public class Program
    {
        public static Dictionary<Level, int> errorCount;

        public static Level minimumLevel = Level.Info;

        public static void Main(string[] args)
        {
            errorCount = new Dictionary<Level, int>();

            // Remove before checkin
            // args = new string[1] { @"C:\Code\Github\GuidRandomiser\example.json" };

            if (args != null && args.Count() > 0)
            {
                // Get the argument - this is a single filename.
                var fileName = args.First().Trim();
                
                RandomiseGuids(fileName, fileName + ".rnd");
            }
            else
            {
                WriteOutput(Level.Error, "This tool replaces all guids in a document with new randomized guids. Copies of the same guid are replaced with the same random guid, preserving links. Please include the filename of a file as the argument.");
            }

            Console.WriteLine();
            foreach (var kvp in errorCount)
            {
                Console.WriteLine($"Number of messages with level '{kvp.Key}': {kvp.Value}");
            }

            Console.ReadLine();
        }

        private static void RandomiseGuids(string fileName, string outputFileName)
        {
            WriteOutput(Level.Info, $"Processing file '{fileName}'");
            
            var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            var fileContents = String.Empty;
            using (StreamReader r = new StreamReader(stream))
            {
                fileContents = r.ReadToEnd();
            }

            // Compile a list of all the guids in this file.
            var matches = Regex.Matches(fileContents, @"[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}");

            var allGuids = new List<string>();
            foreach (Match match in matches)
            {
                allGuids.Add(match.Value);
            }
            
            var distinctGuids = allGuids.Distinct().ToList();
            var distinctGuidsCount = distinctGuids.Count();

            WriteOutput(Level.Info, $"Found {allGuids.Count} total guids ({distinctGuidsCount} unique guids) in file {fileName}.");

            // Replace each guid with a randomized guid.
            var replacements = 0;
            foreach (var guid in distinctGuids)
            {
                fileContents = fileContents.Replace(guid, Guid.NewGuid().ToString());
                replacements++;
                if (replacements % 50 == 0)
                {
                    int percentComplete = (int)Math.Floor(((double)replacements / (double)distinctGuidsCount) * (double)100);
                    WriteOutput(Level.Info, $"Replaced {replacements} guids. {percentComplete}% complete.");
                }
            }
            
            WriteOutput(Level.Info, $"Replaced {replacements}/{distinctGuidsCount} guids. 100% complete.");

            // Write the file.
            var writeStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
            using (StreamWriter sw = new StreamWriter(writeStream))
            {
                sw.WriteLine(fileContents);
            }

            WriteOutput(Level.Info, $"Finished writing updated file: {fileName}");
        }

        private static void WriteOutput(Level level, string message)
        {
            if (level >= minimumLevel)
            {
                Console.WriteLine($"{level.ToString()}: {message}");
            }

            if (errorCount.TryGetValue(level, out int value))
            {
                errorCount.Remove(level);
            }

            value++;
            errorCount.Add(level, value);
        }
    }
}