namespace ConfigFileManager.Controls.FileSelector;

public partial class DirectorySelector : UserControl
{
    public DirectorySelector()
    {
        InitializeComponent();
    }

    public string Extension
    {
        get { return (string)GetValue(ExtensionProperty); }
        set { SetValue(ExtensionProperty, value); }
    }

    public static readonly DependencyProperty ExtensionProperty =
        DependencyProperty.Register("Extension", typeof(string), typeof(DirectorySelector), new PropertyMetadata(default));

    public ObservableCollection<FileDisplay> Displays
    {
        get { return (ObservableCollection<FileDisplay>)GetValue(DisplaysProperty); }
        set { SetValue(DisplaysProperty, value); }
    }

    public static readonly DependencyProperty DisplaysProperty =
        DependencyProperty.Register("Displays", typeof(ObservableCollection<FileDisplay>), typeof(DirectorySelector), new PropertyMetadata(default));

    public ObservableDictionary<int, FileDisplay> Parents
    {
        get { return (ObservableDictionary<int, FileDisplay>)GetValue(ParentsProperty); }
        set { SetValue(ParentsProperty, value); }
    }

    public static readonly DependencyProperty ParentsProperty =
        DependencyProperty.Register("Parents", typeof(ObservableDictionary<int, FileDisplay>), typeof(DirectorySelector), new PropertyMetadata(default));



    public string Title
    {
        get { return (string)GetValue(TitleProperty); }
        set { SetValue(TitleProperty, value); }
    }

    public static readonly DependencyProperty TitleProperty =
        DependencyProperty.Register("Title", typeof(string), typeof(DirectorySelector), new PropertyMetadata(default));



    public string InitialPath
    {
        get { return (string)GetValue(InitialPathProperty); }
        set { SetValue(InitialPathProperty, value); }
    }

    public static readonly DependencyProperty InitialPathProperty =
        DependencyProperty.Register("InitialPath", typeof(string), typeof(DirectorySelector), new PropertyMetadata(default, PropertyChangedCallback));

    private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not DirectorySelector selector)
            return;

        if (e.NewValue is not string path)
            return;


        selector.Displays ??= [];
        selector.Displays.Clear();
        selector.Parents ??= [];
        selector.Parents.Clear();
        DirectoryInfo? temp = new(path);

        selector.SetCurrent(temp);
    }


    private string _Current = "";

    private static void GetFullPath(DirectoryInfo dir, ref List<FileDisplay> paths)
    {
        paths ??= [];
        FileDisplay display = new()
        {
            Name = dir.Name,
            Path = dir.FullName,
            ImageSource = Application.Current.Resources["Icon_Folder"],
            Type = DisType.Folder
        };
        paths.Add(display);

        if (dir.Parent is not null)
            GetFullPath(dir.Parent, ref paths);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var t = (Button)e.Source;
        FileDisplay d = (FileDisplay)t.CommandParameter;
        if (string.IsNullOrEmpty(d.Path))
            return;

        if (d.Type == DisType.File)
        {
            try
            {
                System.Diagnostics.Process.Start("notepad.exe", d.Path);
            }
            catch
            {
            }
            return;
        }

        DirectoryInfo dir = new(d.Path);

        List<FileDisplay> s = [];
        GetFullPath(dir, ref s);
        Parents ??= [];
        Parents.Clear();
        for (int i = s.Count - 1; i >= 0; i--)
        {
            Parents[i] = s[i];
        }

        Displays ??= [];
        Displays.Clear();
        _Current = d.Path;

        FileInfo[] files = dir.GetFiles();
        DirectoryInfo[] dics = dir.GetDirectories();

        foreach (DirectoryInfo item in dics)
        {
            if (item.Attributes.HasFlag(FileAttributes.Hidden))
                continue;
            if (item.Name.StartsWith('.'))
                continue;

            FileDisplay display = new()
            {
                Name = item.Name,
                Path = item.FullName,
                ImageSource = Application.Current.Resources["Icon_Folder"],
                Type = DisType.Folder
            };
            Displays.Add(display);
        }

        foreach (var item in files)
        {
            if (item.Attributes.HasFlag(FileAttributes.Hidden))
                continue;
            if (this.Extension is not null && item.Extension != this.Extension)
                continue;
            FileDisplay display = new()
            {
                Name = item.Name.Remove(item.Name.LastIndexOf(item.Extension), item.Extension.Length),
                Path = item.FullName,
                ImageSource = Application.Current.Resources["Icon_File"],
                FileType = item.Extension,
                Type = DisType.File
            };
            Displays.Add(display);
        }
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrEmpty(_Current))
            return;
        if (_Current == InitialPath)
        {
            return;
        }

        Displays ??= [];
        Displays.Clear();
        Parents ??= [];
        Parents.Clear();
        DirectoryInfo? temp = new DirectoryInfo(_Current).Parent;

        this.SetCurrent(temp);
    }

    private void SetCurrent(DirectoryInfo? directoryInfo)
    {
        DirectoryInfo? temp = directoryInfo;
        if (temp is null)
        {
            DriveInfo[] drives = DriveInfo.GetDrives();

            foreach (DriveInfo basePath in drives)
            {
                FileDisplay display = new()
                {
                    Name = basePath.Name,
                    Path = basePath.Name,
                    ImageSource = Application.Current.Resources["Icon_Folder"],
                    Type = DisType.Folder
                };
                Displays.Add(display);
            }
            return;
        }

        List<FileDisplay> s = [];
        GetFullPath(temp, ref s);

        for (int i = s.Count - 1; i >= 0; i--)
        {
            Parents[i] = s[i];
        }


        _Current = temp.FullName;
        FileInfo[] files = new DirectoryInfo(_Current).GetFiles();
        DirectoryInfo[] dics = new DirectoryInfo(_Current).GetDirectories();

        foreach (DirectoryInfo item in dics)
        {
            if (item.Attributes.HasFlag(FileAttributes.Hidden))
                continue;
            if (item.Name.StartsWith('.'))
                continue;
            if (!string.IsNullOrEmpty(this.Extension) && this.Extension != item.Extension)
                continue;

            FileDisplay display = new()
            {
                Name = item.Name,
                Path = item.FullName,
                ImageSource = Application.Current.Resources["Icon_Folder"],
                Type = DisType.Folder
            };
            Displays.Add(display);
        }

        foreach (var item in files)
        {
            if (item.Attributes.HasFlag(FileAttributes.Hidden))
                continue;

            if (!string.IsNullOrEmpty(this.Extension) && this.Extension != item.Extension)
                continue;

            FileDisplay display = new()
            {
                Name = item.Name.Replace(item.Extension, ""),
                Path = item.FullName,
                ImageSource = Application.Current.Resources["Icon_File"],
                FileType = item.Extension,
                Type = DisType.File
            };
            Displays.Add(display);
        }
    }
}

public partial class FileDisplay : ObservableObject
{
    [ObservableProperty]
    private string? _Name;

    [ObservableProperty]
    private string? _Path;
    [ObservableProperty]
    private object? _ImageSource;
    [ObservableProperty]
    private object? _FileType;
    [ObservableProperty]
    private DisType _Type;
}

public enum DisType
{
    File,
    Folder
}