using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DataOrganizer
{
    public partial class FileViewer : Form
    {
        private Dictionary<string, DB.Profile> Profiles { get; } = new Dictionary<string, DB.Profile>();
        private Dictionary<string, DB.FolderGroup> FolderGroups { get; } = new Dictionary<string, DB.FolderGroup>();
        private string CurrentNamingPattern { get; set; } = string.Empty;
        private ContextMenu PrimaryTreeContextMenu { get; set; } = new ContextMenu(); //Copy to default new content location, set new naming rules etc..
        private Snapshot ActiveSnapshotForPrimaryTree { get; set; }
        private Dictionary<string, TreeNode> PrimaryTreeNodes { get; set; } = new Dictionary<string, TreeNode>();

        public FileViewer()
        {
            InitializeComponent();
            var db = new DB();

            var profiles = db.GetProfiles();

            foreach(var profile in profiles)
            {
                ProfileComboBox.Items.Add(profile.Name);
                Profiles.Add(profile.Name, profile);
            }

            ProfileComboBox.SelectedIndexChanged += ProfileComboBox_SelectedIndexChanged;
            RootFolderComboBox.SelectedIndexChanged += SelectedFolderComboBox_SelectedIndexChanged;
            PrimaryFilesTreeView.NodeMouseClick += PrimaryFilesTreeView_NodeMouseClick;
            FolderSelectButton.Click += FolderSelectButton_Click1;

            ProfileComboBox.SelectedIndex = 0;
        }

        private void FolderSelectButton_Click1(object sender, EventArgs e)
        {
            WriteFilesToDb(GetActiveFolderGroup().Path);
        }

        private void PrimaryFilesTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if(ActiveSnapshotForPrimaryTree.Files.ContainsKey(e.Node.Name))
            {
                var file = ActiveSnapshotForPrimaryTree.Files[e.Node.Name];

                FileDetailsNameLabel.Text = $"Name: {file.Name}";
                FileDetailsFullPathLabel.Text = $"Full Path: {file.FullPath}";
            }
        }

        private void SelectedFolderComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            var db = new DB();

            var folderGroup = FolderGroups[RootFolderComboBox.Text];
            CurrentNamingPattern = db.GetNamingPatternById(folderGroup.PatternId);
            var profile = Profiles[ProfileComboBox.Text];

            PrimaryFilesTreeView.Nodes.Clear();
            PrimaryTreeNodes.Clear();

            var files = db.GetFilesForProfileByFolderGroup(profile.Id, folderGroup.Id);
            ActiveSnapshotForPrimaryTree = new Snapshot(files, folderGroup);

            //if(ActiveSnapshotForPrimaryTree.Directories.ContainsKey(@"W:\Test\Amagi Brilliant Park\Season 1")) ActiveSnapshotForPrimaryTree.DeleteFolder(ActiveSnapshotForPrimaryTree.Directories[@"W:\Test\Amagi Brilliant Park\Season 1"]);

            foreach(var folder in ActiveSnapshotForPrimaryTree.Root.Folders)
            {
                PrimaryFilesTreeView.Nodes.Add(GetNodeFromSnapshot(folder));
            }
        }

        private TreeNode GetNodeFromSnapshot(KeyValuePair<string, Folder> folder)
        {
            var node = new TreeNode(folder.Value.Name) { Name = folder.Key, ToolTipText = folder.Key };
            var regex = new Regex(CurrentNamingPattern);

            foreach(var f in folder.Value.Folders)
            {
                var folderNode = GetNodeFromSnapshot(f);
                //PrimaryTreeNodes.Add(f.Key, folderNode);
                node.Nodes.Add(folderNode);
                if (folderNode.ForeColor == Color.Orange)
                {
                    node.ForeColor = folderNode.ForeColor;
                    node.ToolTipText = "Naming violations found!";
                }
            }

            foreach(var file in folder.Value.Files)
            {
                var fileNode = new TreeNode(file.Value.Name) { Name = file.Key, ToolTipText = file.Key };
                //PrimaryTreeNodes.Add(file.Key, fileNode);

                if (!regex.IsMatch(file.Value.Name)) fileNode.ForeColor = Color.Orange;

                node.Nodes.Add(fileNode);
                if(node.ForeColor != Color.Orange) node.ForeColor = fileNode.ForeColor;
                PrimaryTreeNodes.Add(file.Key, fileNode);
            }

            PrimaryTreeNodes.Add(folder.Key, node);

            return node;
        }

        private void ProfileComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            var profile = Profiles[ProfileComboBox.Text];

            RootFolderComboBox.Items.Clear();
            PrimaryTreeNodes.Clear();
            FolderGroups.Clear();

            if (profile.FolderGroups.Count > 0)
            {
                foreach (var folder in profile.FolderGroups)
                {
                    RootFolderComboBox.Items.Add(folder.Name);
                    FolderGroups.Add(folder.Name, folder);
                }

                RootFolderComboBox.SelectedIndex = 0;
            }

            RootFolderComboBox.Enabled = true;
        }

        private void FolderSelectButton_Click(object sender, EventArgs e)
        {
            //var folder = FolderGroups[RootFolderComboBox.Text];
            //var profile = Profiles[ProfileComboBox.Text];
            //var db = new DB();

            //StatusLabel.Text = $"{db.GetNamingPatternById(folder.PatternId)}";
            //StatusStrip.Refresh();

            //PrimaryFilesTreeView.Nodes.Clear();

            //var files = db.GetFilesForProfileByFolderGroup(profile.Id, folder.Id);

            //if (files.Count == 0) return;

            //var fileInfos = new List<FileInfo>();

            //foreach(var file in files)
            //{
            //    fileInfos.Add(new FileInfo(file.FullPath));
            //}
        }

        private void ScanRootFolderButton_Click(object sender, EventArgs e)
        {
            var folderGroup = GetActiveFolderGroup();
            var files = new List<FileInfo>();
            var rootFolder = new DirectoryInfo(folderGroup.Path);

            foreach (var dir in rootFolder.EnumerateDirectories()) 
                files.AddRange(ScanDirectory(dir));

            var snapShot = new Snapshot(files, folderGroup);
            ActiveSnapshotForPrimaryTree.MergeSnapshot(snapShot);

            var newFiles = snapShot.Files.Values.Except(ActiveSnapshotForPrimaryTree.Files.Values);
            var existingFiles = ActiveSnapshotForPrimaryTree.Files.Values.Except(snapShot.Files.Values);
            var newFilesCount = 0;
            var modifiedFilesCount = 0;
            var deletedFilesCount = 0;

            foreach(var f in newFiles)
            {
                var newNode = new TreeNode(f.Name) { Name = f.FullPath, BackColor = Color.LightBlue, ToolTipText = "New File Found!" };
                var folders = ProcessFileFolders(f);
                Folder previousFolder = null;

                foreach(var folder in folders)
                {
                    var node = new TreeNode(folder.Name) { Name = folder.FullPath, BackColor = Color.LightBlue, ToolTipText = "New file found!" };

                    if (previousFolder == null && !PrimaryTreeNodes.ContainsKey(folder.FullPath)) PrimaryFilesTreeView.Nodes.Add(node);

                    if (!PrimaryTreeNodes.ContainsKey(folder.FullPath))
                    {
                        PrimaryTreeNodes.Add(folder.FullPath, node);
                        if (previousFolder != null) PrimaryTreeNodes[previousFolder.FullPath].Nodes.Add(node);
                    }

                    previousFolder = folder;
                }

                if (!PrimaryTreeNodes.ContainsKey(f.FullPath))
                {
                    PrimaryTreeNodes.Add(f.FullPath, newNode);
                    PrimaryTreeNodes[f.ParentFolder.FullPath].Nodes.Add(newNode);
                    newFilesCount++;
                }
            }

            foreach(var f in ActiveSnapshotForPrimaryTree.Files.Where(x => x.Value.Status == FileSnapshot.FileStatus.PendingDelete))
            {
                PrimaryTreeNodes[f.Key].BackColor = Color.Red;
                PrimaryTreeNodes[f.Key].ToolTipText = "This file has been deleted.";
                deletedFilesCount++;
            }

            foreach(var f in ActiveSnapshotForPrimaryTree.Files.Where(x => x.Value.Status == FileSnapshot.FileStatus.PendingUpdate))
            {
                PrimaryTreeNodes[f.Key].BackColor = Color.DarkBlue;
                PrimaryTreeNodes[f.Key].ToolTipText = "This file has been modified.";
                modifiedFilesCount++;
            }

            label8.Text = $"New Files: {newFilesCount}{Environment.NewLine}Modified Files: {modifiedFilesCount}{Environment.NewLine}Deleted Files: {deletedFilesCount}";
        }

        private List<Folder> ProcessFileFolders(FileSnapshot file)
        {
            var folders = new List<Folder>();
            Folder folder = file.ParentFolder;
            var folderGroup = GetActiveFolderGroup();

            while(folder != null)
            {
                if(folder.FullPath != folderGroup.Path) folders.Add(folder);
                folder = folder.Parent;
            }

            folders.Reverse();

            return folders;
        }

        private List<FileInfo> ScanDirectory(DirectoryInfo dir)
        {
            var files = new List<FileInfo>();

            files.AddRange(dir.EnumerateFiles());

            foreach (var folder in dir.EnumerateDirectories())
                files.AddRange(ScanDirectory(folder));

            return files;
        }
        private void WriteFilesToDb(string root)
        {
            var dir = new DirectoryInfo(root);
            var folder = FolderGroups[RootFolderComboBox.Text];
            var profile = Profiles[ProfileComboBox.Text];
            //var db = new DB();
            //var pattern = db.GetNamingPatternById(folder.PatternId);

            WriteFilesInFolderToDb(dir.FullName, profile.Id, folder.Id, root);
            UpdateStatusStrip("Finished processing files.");
        }

        private void WriteFilesInFolderToDb(string path, int profileId, int folderId, string root)
        {
            var dir = new DirectoryInfo(path);
            var db = new DB();

            var files = GetFileSnapshots(dir.FullName);

            if(files.Count > 0 ) db.InsertNewFileRecord(files, profileId, folderId, root);

            foreach(var d in dir.EnumerateDirectories())
            {
                UpdateStatusStrip($"Processing {d.FullName}");

                WriteFilesInFolderToDb(d.FullName, profileId, folderId, root);
            }
        }

        private List<DB.FileSnapshot> GetFileSnapshots(string path)
        {
            var dir = new DirectoryInfo(path);
            var profile = GetActiveProfile();
            var folderGroup = GetActiveFolderGroup();

            var snapshots = new List<DB.FileSnapshot>();

            foreach(var file in dir.EnumerateFiles())
            {
                snapshots.Add(new DB.FileSnapshot
                {
                    PathNoRoot = file.FullName,
                    Name = file.Name,
                    CreationDate = file.CreationTimeUtc,
                    ModifiedDate = file.LastWriteTimeUtc,
                    ProfileId = profile.Id,
                    RootFolderId = folderGroup.Id,
                    Size = file.Length,
                    PatternId = 0 //TODO: Add something that let's the user override the global pattern.
                });
            }

            return snapshots;
        }

        private DB.Profile GetActiveProfile()
        {
            return Profiles[ProfileComboBox.Text];
        }

        private DB.FolderGroup GetActiveFolderGroup()
        {
            return FolderGroups[RootFolderComboBox.Text];
        }

        private void UpdateStatusStrip(string message)
        {
            StatusLabel.Text = message;
            StatusStrip.Refresh();
        }
    }
}
