using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;

namespace UnshackleGUI
{
    public partial class MainForm : Form
    {
        // =========================================================
        // 1. VARIABLES
        // =========================================================
        private string _configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
        private string _paramsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "params.json");
        private string _profilesDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles");

        private AppSettings _appSettings = new AppSettings();
        private List<UnshackleParameter> _parameterDefinitions = new List<UnshackleParameter>();
        private Dictionary<string, object> _propertyValues = new Dictionary<string, object>();

        private Process? _currentProcess;
        private bool _isLoaded = false;
        private string _lastLoadedProfile = "";

        // Scheduler Reference
        private SchedulerForm? _scheduler = null;

        // =========================================================
        // 2. CONSTRUCTOR
        // =========================================================
        public MainForm()
        {
            InitializeComponent();
           // ApplyDarkTheme();

            if (!Directory.Exists(_profilesDir))
            {
                Directory.CreateDirectory(_profilesDir);
            }

            SetupEventHandlers();
            LoadData();
        }

        private void SetupEventHandlers()
        {
            // Property Grid
            pgProfile.PropertyValueChanged += (s, e) =>
            {
                UpdateCommandPreview();
                SaveCurrentProfile();
            };

            // Service Dropdown
            comboService.SelectedIndexChanged += (s, e) =>
            {
                if (!_isLoaded) return;

                if (comboService.SelectedItem != null)
                {
                    _propertyValues["Service"] = comboService.SelectedItem.ToString();
                    UpdateCommandPreview();
                    SaveCurrentProfile();
                }
            };

            // Text Boxes
            txtURL.TextChanged += (s, e) => UpdateCommandPreview();

            txtBinName.TextChanged += (s, e) =>
            {
                UpdateCommandPreview();
                SaveGlobalConfig();
            };

            txtRootPath.TextChanged += (s, e) => SaveGlobalConfig();

            // Main Buttons
            btnRun.Click += btnRun_Click;
            btnStop.Click += btnStop_Click;
            btnBrowse.Click += btnBrowse_Click;
            btnOpenCookies.Click += btnOpenCookies_Click;
            btnEditServiceConfig.Click += btnEditServiceConfig_Click;
            btnClearLog.Click += btnClearLog_Click;
            btnEditYaml.Click += btnEditYaml_Click;
            btnAddProfile.Click += btnAddProfile_Click;
            btnRemoveProfile.Click += btnRemoveProfile_Click;
            btnSaveProfile.Click += btnSaveProfile_Click;

            // Scheduler Buttons
            btnToggleScheduler.Click += BtnToggleScheduler_Click;
            // btnScheduler click is already wired in Designer or can be added here:
            // btnScheduler.Click += BtnScheduler_Click; 
        }

        // =========================================================
        // 3. SCHEDULER LOGIC (OPEN & TOGGLE)
        // =========================================================

        // A. THE CLOCK BUTTON: Opens the window
        private void BtnScheduler_Click(object sender, EventArgs e)
        {
            // If it doesn't exist, create it (auto-starts timer)
            if (_scheduler == null || _scheduler.IsDisposed)
            {
                CreateScheduler();
            }

            // Show it
            if (!_scheduler.Visible)
            {
                _scheduler.Show();
            }

            _scheduler.BringToFront();
        }

        // B. THE START/STOP BUTTON: Controls the process
        private void BtnToggleScheduler_Click(object sender, EventArgs e)
        {
            if (_scheduler != null && !_scheduler.IsDisposed)
            {
                // STOPPING
                _scheduler.Shutdown();
                _scheduler = null;
                UpdateSchedulerButtonState(false);
                MessageBox.Show("Scheduler stopped.", "Unshackle", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                // STARTING
                CreateScheduler();
                // We create it but don't show the window yet (runs in background)
                MessageBox.Show("Scheduler started in background.", "Unshackle", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void CreateScheduler()
        {
            var profiles = comboProfiles.Items.Cast<string>().ToList();
            _scheduler = new SchedulerForm(profiles, txtRootPath.Text, txtBinName.Text);
            UpdateSchedulerButtonState(true);
        }

        private void UpdateSchedulerButtonState(bool isRunning)
        {
            if (isRunning)
            {
                // Running State -> Show STOP button (Red)
                btnToggleScheduler.Text = "🛑 Stop Scheduler";
                btnToggleScheduler.ForeColor = Color.Red;
            }
            else
            {
                // Stopped State -> Show START button (Green)
                btnToggleScheduler.Text = "▶ Start Scheduler";
                btnToggleScheduler.ForeColor = Color.LightGreen;
            }
        }

        // =========================================================
        // 4. DATA LOADING
        // =========================================================
        private void LoadData()
        {
            _isLoaded = false;

            if (File.Exists(_paramsPath))
            {
                var json = File.ReadAllText(_paramsPath);
                _parameterDefinitions = JsonConvert.DeserializeObject<List<UnshackleParameter>>(json) ?? new List<UnshackleParameter>();
            }
            else
            {
                MessageBox.Show("Error: params.json not found!");
            }

            if (File.Exists(_configPath))
            {
                var json = File.ReadAllText(_configPath);
                _appSettings = JsonConvert.DeserializeObject<AppSettings>(json) ?? new AppSettings();

                txtRootPath.Text = _appSettings.RootPath;
                txtBinName.Text = _appSettings.BinaryName;
            }

            RefreshFolders();
            RefreshProfileList();

            _isLoaded = true;
            UpdateCommandPreview();
        }

        private void RefreshProfileList()
        {
            comboProfiles.SelectedIndexChanged -= ComboProfiles_SelectedIndexChanged;

            var files = Directory.GetFiles(_profilesDir, "*.json");
            var profileNames = files.Select(Path.GetFileNameWithoutExtension).ToList();

            if (profileNames.Count == 0)
            {
                CreateDefaultProfile();
                profileNames.Add("Default");
            }

            comboProfiles.DataSource = null;
            comboProfiles.DataSource = profileNames;

            string targetProfile = profileNames.Contains("Default") ? "Default" : profileNames[0];
            comboProfiles.SelectedItem = targetProfile;

            LoadProfile(targetProfile);

            comboProfiles.SelectedIndexChanged += ComboProfiles_SelectedIndexChanged;
        }

        private void CreateDefaultProfile()
        {
            _propertyValues = new Dictionary<string, object>();

            foreach (var p in _parameterDefinitions)
            {
                _propertyValues[p.Name] = p.Default ?? "";
            }

            if (comboService.Items.Count > 0)
            {
                _propertyValues["Service"] = comboService.Items[0].ToString();
            }

            SaveProfileFile("Default");
        }

        private void ComboProfiles_SelectedIndexChanged(object? sender, EventArgs e)
        {
            if (comboProfiles.SelectedItem == null) return;
            LoadProfile(comboProfiles.SelectedItem.ToString());
        }

        private void LoadProfile(string profileName)
        {
            _lastLoadedProfile = profileName;
            string path = Path.Combine(_profilesDir, $"{profileName}.json");

            if (!File.Exists(path)) return;

            try
            {
                var json = File.ReadAllText(path);
                var loadedValues = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

                if (loadedValues != null)
                {
                    _propertyValues = loadedValues;

                    foreach (var p in _parameterDefinitions)
                    {
                        if (!_propertyValues.ContainsKey(p.Name))
                        {
                            _propertyValues[p.Name] = p.Default ?? "";
                        }
                    }

                    if (_propertyValues.TryGetValue("Service", out var serviceObj))
                    {
                        string serviceName = serviceObj.ToString();
                        if (comboService.Items.Contains(serviceName))
                        {
                            bool wasLoaded = _isLoaded;
                            _isLoaded = false;
                            comboService.SelectedItem = serviceName;
                            _isLoaded = wasLoaded;
                        }
                    }
                    else if (comboService.SelectedItem != null)
                    {
                        _propertyValues["Service"] = comboService.SelectedItem.ToString();
                    }

                    pgProfile.SelectedObject = new DynamicObject(_propertyValues, _parameterDefinitions);
                    pgProfile.Refresh();

                    UpdateCommandPreview();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Error loading profile: {ex.Message}");
            }
        }

        private void SaveCurrentProfile()
        {
            if (!_isLoaded || comboProfiles.SelectedItem == null) return;
            string name = comboProfiles.SelectedItem.ToString();
            SaveProfileFile(name);
        }

        private void SaveProfileFile(string name)
        {
            try
            {
                if (comboService.SelectedItem != null)
                {
                    _propertyValues["Service"] = comboService.SelectedItem.ToString();
                }

                string path = Path.Combine(_profilesDir, $"{name}.json");
                File.WriteAllText(path, JsonConvert.SerializeObject(_propertyValues, Formatting.Indented));
            }
            catch (Exception ex)
            {
                AppendLog($"[Error Saving Profile]: {ex.Message}");
            }
        }

        private void SaveGlobalConfig()
        {
            if (!_isLoaded) return;

            _appSettings.RootPath = txtRootPath.Text;
            _appSettings.BinaryName = txtBinName.Text;

            try
            {
                File.WriteAllText(_configPath, JsonConvert.SerializeObject(_appSettings, Formatting.Indented));
            }
            catch
            {
                // Ignore errors
            }
        }

        private void UpdateCommandPreview()
        {
            if (!_isLoaded) return;

            StringBuilder sb = new StringBuilder();
            sb.Append($"{txtBinName.Text} run unshackle dl ");

            foreach (var p in _parameterDefinitions)
            {
                if (!_propertyValues.TryGetValue(p.Name, out object val)) continue;

                if (p.Type == "Bool" && val is bool isTrue && isTrue)
                {
                    sb.Append($"{p.Flag} ");
                }
                else if (p.Type != "Bool" && val != null)
                {
                    string sVal = val.ToString();

                    if (!string.IsNullOrWhiteSpace(sVal) && sVal != "any" && sVal != "0")
                    {
                        if (sVal.Contains(" "))
                        {
                            sVal = $"\"{sVal}\"";
                        }
                        sb.Append($"{p.Flag} {sVal} ");
                    }
                }
            }

            sb.Append($"{comboService.Text} {txtURL.Text}");
            txtCommandPreview.Text = sb.ToString();
        }

        // =========================================================
        // 8. CLI EXECUTION
        // =========================================================
        private async void btnRun_Click(object? sender, EventArgs e)
        {
            string finalCmd = txtCommandPreview.Text;

            if (string.IsNullOrWhiteSpace(finalCmd)) return;

            ToggleUI(true);
            txtLog.AppendText($"> Executing: {finalCmd}{Environment.NewLine}");

            try
            {
                await Task.Run(() => RunCli(finalCmd));
            }
            catch (Exception ex)
            {
                AppendLog($"[ERROR]: {ex.Message}");
            }
            finally
            {
                ToggleUI(false);
            }
        }

        private void RunCli(string cmd)
        {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = "cmd.exe";
            psi.Arguments = $"/c chcp 65001 && {cmd}";
            psi.WorkingDirectory = txtRootPath.Text;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            psi.CreateNoWindow = true;
            psi.StandardOutputEncoding = Encoding.UTF8;

            psi.EnvironmentVariables["PYTHONIOENCODING"] = "utf-8";

            using (_currentProcess = Process.Start(psi))
            {
                if (_currentProcess == null) return;

                _currentProcess.OutputDataReceived += (s, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data) && !e.Data.Contains("Active code page"))
                    {
                        AppendLog(e.Data);
                    }
                };

                _currentProcess.ErrorDataReceived += (s, e) => AppendLog(e.Data);

                _currentProcess.BeginOutputReadLine();
                _currentProcess.BeginErrorReadLine();
                _currentProcess.WaitForExit();
            }
        }

        // =========================================================
        // 9. HELPER METHODS
        // =========================================================
        private void btnAddProfile_Click(object? sender, EventArgs e)
        {
            string name = Microsoft.VisualBasic.Interaction.InputBox("Enter profile name:", "New Profile", "");

            if (string.IsNullOrWhiteSpace(name)) return;

            foreach (char c in Path.GetInvalidFileNameChars())
            {
                name = name.Replace(c, '_');
            }

            if (File.Exists(Path.Combine(_profilesDir, $"{name}.json")))
            {
                MessageBox.Show("Profile already exists.");
                return;
            }

            SaveProfileFile(name);
            RefreshProfileList();
            comboProfiles.SelectedItem = name;
        }

        private void btnRemoveProfile_Click(object? sender, EventArgs e)
        {
            if (comboProfiles.SelectedItem == null) return;

            string selected = comboProfiles.SelectedItem.ToString();

            if (selected == "Default")
            {
                MessageBox.Show("Default profile cannot be deleted.");
                return;
            }

            string path = Path.Combine(_profilesDir, $"{selected}.json");

            if (File.Exists(path))
            {
                File.Delete(path);
            }

            RefreshProfileList();
        }

        private void btnSaveProfile_Click(object? sender, EventArgs e)
        {
            string newName = comboProfiles.Text.Trim();

            if (string.IsNullOrWhiteSpace(newName))
            {
                MessageBox.Show("Please enter a profile name.");
                return;
            }

            foreach (char c in Path.GetInvalidFileNameChars())
            {
                newName = newName.Replace(c, '_');
            }

            if (newName != _lastLoadedProfile && !string.IsNullOrEmpty(_lastLoadedProfile))
            {
                if (_lastLoadedProfile == "Default")
                {
                    SaveProfileFile(newName);
                    RefreshProfileList();
                    comboProfiles.SelectedItem = newName;
                    MessageBox.Show($"Created new profile '{newName}' from Default.", "New Profile Created");
                    return;
                }

                DialogResult choice = MessageBox.Show(
                    $"You changed the name from '{_lastLoadedProfile}' to '{newName}'.\n\n" +
                    "Click YES to RENAME (Delete old).\n" +
                    "Click NO to CREATE COPY (Keep old).",
                    "Rename or Copy?",
                    MessageBoxButtons.YesNoCancel,
                    MessageBoxIcon.Question);

                if (choice == DialogResult.Cancel) return;

                if (choice == DialogResult.Yes)
                {
                    SaveProfileFile(newName);
                    string oldPath = Path.Combine(_profilesDir, $"{_lastLoadedProfile}.json");
                    if (File.Exists(oldPath)) File.Delete(oldPath);

                    RefreshProfileList();
                    comboProfiles.SelectedItem = newName;
                    MessageBox.Show($"Renamed to '{newName}'.");
                }
                else
                {
                    SaveProfileFile(newName);
                    RefreshProfileList();
                    comboProfiles.SelectedItem = newName;
                    MessageBox.Show($"Created copy '{newName}'.");
                }
            }
            else
            {
                SaveProfileFile(newName);
                MessageBox.Show($"Profile '{newName}' saved!", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void AppendLog(string? text)
        {
            if (string.IsNullOrEmpty(text)) return;

            this.BeginInvoke(new Action(() =>
            {
                txtLog.AppendText(text + Environment.NewLine);
            }));
        }

        private void ToggleUI(bool isRunning)
        {
            this.BeginInvoke(new Action(() =>
            {
                btnRun.Enabled = !isRunning;
                btnStop.Visible = isRunning;
            }));
        }

        private void btnStop_Click(object? sender, EventArgs e)
        {
            if (_currentProcess != null && !_currentProcess.HasExited)
            {
                _currentProcess.Kill(true);
            }
        }

        private void btnClearLog_Click(object? sender, EventArgs e)
        {
            txtLog.Clear();
        }

        private void btnBrowse_Click(object? sender, EventArgs e)
        {
            using (var fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    txtRootPath.Text = fbd.SelectedPath;
                    SaveGlobalConfig();
                    RefreshFolders();
                }
            }
        }

        private void btnOpenCookies_Click(object? sender, EventArgs e)
        {
            string path = Path.Combine(txtRootPath.Text, "unshackle", "cookies", comboService.Text);
            Directory.CreateDirectory(path);
            Process.Start("explorer.exe", path);
        }

        private void btnEditYaml_Click(object? sender, EventArgs e)
        {
            string yamlPath = Path.Combine(txtRootPath.Text, "unshackle/unshackle.yaml");
            if (File.Exists(yamlPath))
            {
                Process.Start(new ProcessStartInfo(yamlPath) { UseShellExecute = true });
            }
        }

        private void btnEditServiceConfig_Click(object? sender, EventArgs e)
        {
            string yamlPath = Path.Combine(txtRootPath.Text, "unshackle", "services", comboService.Text, "config.yaml");
            if (File.Exists(yamlPath))
            {
                Process.Start(new ProcessStartInfo(yamlPath) { UseShellExecute = true });
            }
            else
            {
                MessageBox.Show($"No config.yaml found for {comboService.Text}");
            }
        }

        private void RefreshFolders()
        {
            comboService.Items.Clear();
            string path = Path.Combine(txtRootPath.Text, "unshackle", "services");

            if (Directory.Exists(path))
            {
                var dirs = Directory.GetDirectories(path).Select(Path.GetFileName).ToArray();
                comboService.Items.AddRange(dirs.Cast<object>().ToArray());

                if (comboService.Items.Count > 0)
                {
                    comboService.SelectedIndex = 0;
                }
            }
        }



        private void UpdateControlTheme(Control c)
        {
            // --- FIX: DO NOT TOUCH THESE BUTTONS ---
            if (c == btnScheduler || c == btnToggleScheduler || c == btnRun || c == btnStop)
            {
                return;
            }

            // Apply standard dark theme to everything else
            c.BackColor = Color.FromArgb(45, 45, 48);
            c.ForeColor = Color.White;

            if (c is TextBox tb)
            {
                tb.BorderStyle = BorderStyle.FixedSingle;
            }

            if (c is Button btn)
            {
                btn.FlatStyle = FlatStyle.Flat;
                btn.FlatAppearance.BorderColor = Color.Gray;
            }

            if (c is PropertyGrid pg)
            {
                pg.BackColor = Color.FromArgb(37, 37, 38);
                pg.ViewBackColor = Color.FromArgb(37, 37, 38);
                pg.ViewForeColor = Color.White;
                pg.LineColor = Color.FromArgb(45, 45, 48);
            }

            foreach (Control child in c.Controls)
            {
                UpdateControlTheme(child);
            }
        }
    }

    // =========================================================
    // 10. DATA MODELS
    // =========================================================

    public class AppSettings
    {
        public string RootPath { get; set; } = @"C:\DEVINE\unshackle";
        public string BinaryName { get; set; } = "uv";
    }

    public class UnshackleParameter
    {
        public string Flag { get; set; } = "";
        public string Name { get; set; } = "";
        public string Type { get; set; } = "Text";
        public List<string>? Options { get; set; }
        public object? Default { get; set; }
        public string Category { get; set; } = "Misc";
    }
}