using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;
using Inspectron.Settings.Attributes;
using Microsoft.WindowsAPICodePack.Dialogs;

namespace Inspectron.Settings.Windows.Configuration;

public class DefaultControlFactory : IControlFactory
{
    public virtual Control CreateControl(string name, string description, PropertyInfo propertyInfo,
        object initialValue, Action<object> valueChangedCallback, OptionsWindow optionsWindow)
    {
        var type = propertyInfo.PropertyType;

        // Check for SettingDescriptionAttribute
        var settingDescriptionAttribute = propertyInfo.GetCustomAttribute<SettingDescriptionAttribute>();
        string settingDescription = settingDescriptionAttribute?.Description;

        // Check for SettingPreviewAttribute
        var previewAttribute = propertyInfo.GetCustomAttribute<SettingPreviewAttribute>();
        Label previewLabel = null;
        Func<object, string> getPreview = null;

        if (previewAttribute != null)
        {
            var method = previewAttribute.PreviewClass.GetMethod(previewAttribute.PreviewFunction, BindingFlags.Public | BindingFlags.Static);
            getPreview = value => (string)method.Invoke(null, new[] { value });
            previewLabel = new Label
            {
                AutoSize = false,
                Size = new System.Drawing.Size(600, 30),
                Padding = new Padding(15, 0, 0, 0),
                Font = new System.Drawing.Font("Segoe UI", 10, System.Drawing.FontStyle.Italic),
                Text = getPreview(initialValue)
            };
        }

        // Check for List<T> types
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
        {
            return CreateListControl(name, description, type, initialValue, valueChangedCallback, optionsWindow, settingDescription, previewLabel, getPreview);
        }
        else if (type == typeof(string) && propertyInfo.GetCustomAttribute<FileAttribute>()!=null)
        {
            return CreateFileControl(name, description, initialValue, valueChangedCallback, optionsWindow, settingDescription, previewLabel, getPreview, propertyInfo.GetCustomAttribute<FileAttribute>().Filter);
        }
        else if (type == typeof(string) && name.EndsWith("Path", StringComparison.OrdinalIgnoreCase))
        {
            return CreatePathControl(name, description, initialValue, valueChangedCallback, optionsWindow, settingDescription, previewLabel, getPreview);
        }
        else if (type == typeof(string))
        {
            return CreateStringControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
        }
        else if (type == typeof(int))
        {
            return CreateIntControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
        }
        else if (type == typeof(bool))
        {
            return CreateBoolControl(description, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
        }
        else if (type.IsEnum)
        {
            return CreateEnumControl(description, type, initialValue, valueChangedCallback, settingDescription, previewLabel, getPreview);
        }
        else
        {
            return new Label { Text = $"Unsupported type: {type.Name}", AutoSize = true };
        }
    }

    private Control CreateListControl(string name, string description, Type listType, object initialValue, 
        Action<object> valueChangedCallback, OptionsWindow optionsWindow, string settingDescription, 
        Label previewLabel, Func<object, string> getPreview)
    {
        var elementType = listType.GetGenericArguments()[0];
        var list = (IList)initialValue ?? (IList)Activator.CreateInstance(listType);
        
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
        var textBox = new TextBox 
        { 
            Text = GetListDisplayText(list), 
            Width = 500, 
            Height = 60,
            Multiline = true,
            ReadOnly = true,
            ScrollBars = ScrollBars.Vertical
        };
        var editButton = new Button { Text = "Edit", AutoSize = true };

        editButton.Click += (s, e) =>
        {
            using (var listEditor = new ListEditorDialog(elementType, list, this, optionsWindow, name))
            {
                if (listEditor.ShowDialog(optionsWindow) == DialogResult.OK)
                {
                    var newList = listEditor.GetEditedList();
                    list.Clear();
                    foreach (object o in newList)
                    {
                        list.Add(o);
                    }
                    
                    textBox.Text = GetListDisplayText(list);

                    valueChangedCallback(list);
                    if (previewLabel != null && getPreview != null)
                        previewLabel.Text = getPreview(list);
                }
            }
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, textBox, editButton);
    }

    private string GetListDisplayText(IList list)
    {
        if (list == null || list.Count == 0)
            return "(empty list)";
        
        var items = new List<string>();
        foreach (var item in list)
        {
            items.Add(item?.ToString() ?? "(null)");
        }
        return string.Join(Environment.NewLine, items);
    }

    private Control CreatePathControl(string name, string description, object initialValue, Action<object> valueChangedCallback,
        OptionsWindow optionsWindow, string settingDescription, Label previewLabel, Func<object, string> getPreview)
    {
        var textBox = new TextBox { Text = initialValue as string, Width = 400 };
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
        var browseButton = new Button { Text = "Browse", AutoSize = true };

        browseButton.Click += (s, e) =>
        {
            using (var dialog = new CommonOpenFileDialog { IsFolderPicker = true })
            {
                if (dialog.ShowDialog(optionsWindow.Handle) == CommonFileDialogResult.Ok)
                {
                    textBox.Text = dialog.FileName;
                    valueChangedCallback(dialog.FileName);
                    if (previewLabel != null && getPreview != null)
                        previewLabel.Text = getPreview(dialog.FileName);
                }
            }
        };

        textBox.TextChanged += (s, e) =>
        {
            valueChangedCallback(textBox.Text);
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(textBox.Text);
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, textBox, browseButton);
    }
    private Control CreateFileControl(string name, string description, object initialValue, Action<object> valueChangedCallback,
        OptionsWindow optionsWindow, string settingDescription, Label previewLabel, Func<object, string> getPreview, string filter)
    {
        var textBox = new TextBox { Text = initialValue as string, Width = 400 };
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
        var browseButton = new Button { Text = "Browse", AutoSize = true };

        browseButton.Click += (s, e) =>
        {
            using (var dialog = new CommonOpenFileDialog {Filters = { new CommonFileDialogFilter(filter, filter) }})
            {
                if (dialog.ShowDialog(optionsWindow.Handle) == CommonFileDialogResult.Ok)
                {
                    textBox.Text = dialog.FileName;
                    valueChangedCallback(dialog.FileName);
                    if (previewLabel != null && getPreview != null)
                        previewLabel.Text = getPreview(dialog.FileName);
                }
            }
        };

        textBox.TextChanged += (s, e) =>
        {
            valueChangedCallback(textBox.Text);
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(textBox.Text);
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, textBox, browseButton);
    }
    private Control CreateStringControl(string description, object initialValue, Action<object> valueChangedCallback,
        string settingDescription, Label previewLabel, Func<object, string> getPreview)
    {
        var textBox = new TextBox { Text = initialValue as string, Width = 600 };
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };

        textBox.TextChanged += (s, e) =>
        {
            valueChangedCallback(textBox.Text);
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(textBox.Text);
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, textBox);
    }

    private Control CreateIntControl(string description, object initialValue, Action<object> valueChangedCallback,
        string settingDescription, Label previewLabel, Func<object, string> getPreview)
    {
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
        var numericUpDown = new NumericUpDown { Minimum = 0, Maximum = 99999999999, Value = Convert.ToDecimal(initialValue), Width = 200 };

        numericUpDown.ValueChanged += (s, e) =>
        {
            valueChangedCallback(Convert.ToInt32(numericUpDown.Value));
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(Convert.ToInt32(numericUpDown.Value));
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, numericUpDown);
    }

    private Control CreateBoolControl(string description, object initialValue, Action<object> valueChangedCallback,
        string settingDescription, Label previewLabel, Func<object, string> getPreview)
    {
        var checkBox = new CheckBox { Text = description, Checked = (bool)initialValue, AutoSize = true };

        checkBox.CheckedChanged += (s, e) =>
        {
            valueChangedCallback(checkBox.Checked);
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(checkBox.Checked);
        };

        return CreateOuterPanel(settingDescription, previewLabel, checkBox);
    }

    private Control CreateEnumControl(string description, Type enumType, object initialValue, Action<object> valueChangedCallback,
        string settingDescription, Label previewLabel, Func<object, string> getPreview)
    {
        var label = new Label { Text = description, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
        var comboBox = new ComboBox { DropDownStyle = ComboBoxStyle.DropDownList, Width = 200 };

        // Populate ComboBox with enum values
        foreach (var value in Enum.GetValues(enumType))
        {
            comboBox.Items.Add(value);
        }

        // Set initial value
        comboBox.SelectedItem = initialValue;

        comboBox.SelectedIndexChanged += (s, e) =>
        {
            valueChangedCallback(comboBox.SelectedItem);
            if (previewLabel != null && getPreview != null)
                previewLabel.Text = getPreview(comboBox.SelectedItem);
        };

        return CreateOuterPanel(settingDescription, previewLabel, label, comboBox);
    }

    private Control CreateOuterPanel(string settingDescription, Label previewLabel, params Control[] controls)
    {
        var outerPanel = new FlowLayoutPanel { FlowDirection = FlowDirection.TopDown, AutoSize = true, Margin = new Padding(0, 25, 0, 0) };

        if (!string.IsNullOrEmpty(settingDescription))
        {
            var descriptionLabel = new Label { Text = settingDescription, AutoSize = true, Padding = new Padding(0, 5, 0, 0) };
            outerPanel.Controls.Add(descriptionLabel);
        }

        foreach (var control in controls)
        {
            outerPanel.Controls.Add(control);
        }

        if (previewLabel != null)
            outerPanel.Controls.Add(previewLabel);

        return outerPanel;
    }
}

// List Editor Dialog

// Item Editor Dialog

// Helper class for simple property info