using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using AutoIngest.Core;
using AutoIngest.Engine;

namespace AutoIngest.App
{
    /// <summary>
    /// Settings dialog. Houses the device registry (trusted devices, register/remove, prompt
    /// toggle) and the retention section (auto-delete aged folders, age dropdown, access-time
    /// tracking status, and a "run sweep now" button). Themed to match the main toast.
    /// </summary>
    public class SettingsForm : Form
    {
        readonly DeviceRegistry _registry;
        readonly AppConfig _config;
        readonly Func<List<DeviceIdentity>> _getConnected;
        readonly Func<bool> _isAccessTrackingEnabled;
        readonly Func<(int recycled, long bytesReclaimed)> _runSweepNow;

        ListView _devicesList = null!;
        ListView _connectedList = null!;
        CheckBox _promptCheck = null!;
        Button _removeBtn = null!;
        Button _registerBtn = null!;
        Button _closeBtn = null!;

        // Retention controls.
        CheckBox _retentionCheck = null!;
        ComboBox _retentionCombo = null!;
        Label _accessStatus = null!;
        Button _enableAccessBtn = null!;
        Button _sweepNowBtn = null!;

        // Fixed age presets offered in the dropdown, in that order. Days is what's persisted.
        static readonly (string Label, int Days)[] RETENTION_PRESETS =
        {
            ("1 week",    7),
            ("1 month",   30),
            ("3 months",  90),
            ("6 months",  180),
            ("12 months", 365),
            ("2 years",   730),
            ("7 years",   2555),
        };

        public SettingsForm(
            DeviceRegistry registry,
            AppConfig config,
            Func<List<DeviceIdentity>> getConnected,
            Func<bool> isAccessTrackingEnabled,
            Func<(int recycled, long bytesReclaimed)> runSweepNow)
        {
            _registry = registry;
            _config = config;
            _getConnected = getConnected;
            _isAccessTrackingEnabled = isAccessTrackingEnabled;
            _runSweepNow = runSweepNow;
            BuildUi();
            PopulateDevices();
            PopulateConnected();
        }

        void BuildUi()
        {
            Text = "AutoIngest — Settings";
            StartPosition = FormStartPosition.CenterParent;
            ClientSize = new Size(560, 660);
            FormBorderStyle = FormBorderStyle.FixedDialog;
            MaximizeBox = false;
            MinimizeBox = false;
            BackColor = Theme.BG;
            ForeColor = Theme.TEXT;
            Font = new Font("Segoe UI", 9F);

            // --- Registered devices panel ----------------------------------------------
            var lblRegistered = new Label
            {
                Text = "Registered devices (import automatically)",
                Dock = DockStyle.Top,
                Height = 24,
                Padding = new Padding(12, 8, 12, 4),
                ForeColor = Theme.ACCENT,
                BackColor = Theme.BG
            };
            Controls.Add(lblRegistered);

            _devicesList = new ListView
            {
                View = View.Details,
                FullRowSelect = true,
                MultiSelect = false,
                BackColor = Theme.BG_DARK,
                ForeColor = Theme.TEXT,
                HeaderStyle = ColumnHeaderStyle.Nonclickable,
                Font = new Font("Consolas", 8.5F),
                Height = 160,
                Dock = DockStyle.Top
            };
            _devicesList.Columns.Add("Name", 180);
            _devicesList.Columns.Add("Kind", 80);
            _devicesList.Columns.Add("Added", 130);
            _devicesList.Columns.Add("Serial (last 6)", 120);
            Controls.Add(_devicesList);

            // Order matters: Dock.Top fills bottom-up, so add children in reverse visual order.
            _devicesList.BringToFront();
            lblRegistered.SendToBack();

            _removeBtn = new Button
            {
                Text = "Remove selected",
                Dock = DockStyle.Top,
                Height = 28,
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Enabled = false
            };
            _removeBtn.Click += (_, _) => RemoveSelected();
            Controls.Add(_removeBtn);
            _removeBtn.BringToFront();

            // --- Connected devices panel ----------------------------------------------
            var lblConnected = new Label
            {
                Text = "Connected but not registered",
                Dock = DockStyle.Top,
                Height = 24,
                Padding = new Padding(12, 8, 12, 4),
                ForeColor = Theme.ACCENT,
                BackColor = Theme.BG
            };
            Controls.Add(lblConnected);
            lblConnected.BringToFront();

            _connectedList = new ListView
            {
                View = View.Details,
                FullRowSelect = true,
                MultiSelect = false,
                BackColor = Theme.BG_DARK,
                ForeColor = Theme.TEXT,
                HeaderStyle = ColumnHeaderStyle.Nonclickable,
                Font = new Font("Consolas", 8.5F),
                Height = 130,
                Dock = DockStyle.Top
            };
            _connectedList.Columns.Add("Name", 220);
            _connectedList.Columns.Add("Kind", 80);
            _connectedList.Columns.Add("Id", 240);
            Controls.Add(_connectedList);
            _connectedList.BringToFront();
            lblConnected.SendToBack();

            _registerBtn = new Button
            {
                Text = "Register selected",
                Dock = DockStyle.Top,
                Height = 28,
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Enabled = false
            };
            _registerBtn.Click += (_, _) => RegisterSelected();
            Controls.Add(_registerBtn);
            _registerBtn.BringToFront();

            // --- Retention section ----------------------------------------------------
            BuildRetentionSection();

            // --- Bottom row: prompt toggle + close ------------------------------------
            var bottomPanel = new Panel { Dock = DockStyle.Top, Height = 40, BackColor = Theme.BG };
            Controls.Add(bottomPanel);
            bottomPanel.BringToFront();

            _promptCheck = new CheckBox
            {
                Text = "Ask before importing from unknown devices",
                Checked = _config.PromptOnUnknown,
                ForeColor = Theme.TEXT,
                BackColor = Theme.BG,
                AutoSize = false,
                Location = new Point(12, 10),
                Size = new Size(320, 22)
            };
            _promptCheck.CheckedChanged += (_, _) =>
            {
                _config.PromptOnUnknown = _promptCheck.Checked;
                ConfigManager.SaveConfig(_config);
            };
            bottomPanel.Controls.Add(_promptCheck);

            _closeBtn = new Button
            {
                Text = "Close",
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Location = new Point(450, 8),
                Size = new Size(90, 26)
            };
            _closeBtn.Click += (_, _) => Close();
            bottomPanel.Controls.Add(_closeBtn);

            _devicesList.SelectedIndexChanged += (_, _) =>
                _removeBtn.Enabled = _devicesList.SelectedItems.Count > 0;
            _connectedList.SelectedIndexChanged += (_, _) =>
                _registerBtn.Enabled = _connectedList.SelectedItems.Count > 0;

            AcceptButton = _closeBtn;
        }

        /// <summary>
        /// Builds the retention (auto-delete aged folders) section: enable checkbox, age dropdown,
        /// access-tracking status line, enable-access button, and a run-sweep-now button. Sits
        /// above the bottom prompt/close row. Saves config on every change.
        /// </summary>
        void BuildRetentionSection()
        {
            var panel = new Panel
            {
                Dock = DockStyle.Top,
                Height = 150,
                BackColor = Theme.BG
            };
            Controls.Add(panel);

            var lbl = new Label
            {
                Text = "Photo retention (reclaim disk space)",
                Location = new Point(12, 8),
                Size = new Size(540, 22),
                ForeColor = Theme.ACCENT,
                BackColor = Theme.BG
            };
            panel.Controls.Add(lbl);

            _retentionCheck = new CheckBox
            {
                Text = "Auto-delete dated folders older than the selected age",
                Checked = _config.RetentionEnabled,
                Location = new Point(12, 32),
                Size = new Size(420, 22),
                ForeColor = Theme.TEXT,
                BackColor = Theme.BG
            };

            _retentionCombo = new ComboBox
            {
                DropDownStyle = ComboBoxStyle.DropDownList,
                Location = new Point(440, 30),
                Size = new Size(105, 22),
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Enabled = _config.RetentionEnabled
            };
            foreach (var preset in RETENTION_PRESETS)
                _retentionCombo.Items.Add(preset.Label);
            // Select the preset matching the persisted days, or "6 months" default.
            int sel = Array.FindIndex(RETENTION_PRESETS, p => p.Days == _config.RetentionDays);
            _retentionCombo.SelectedIndex = sel >= 0 ? sel : 3; // 3 = "6 months"

            _retentionCheck.CheckedChanged += (_, _) =>
            {
                _config.RetentionEnabled = _retentionCheck.Checked;
                _retentionCombo.Enabled = _retentionCheck.Checked;
                ConfigManager.SaveConfig(_config);
            };
            _retentionCombo.SelectedIndexChanged += (_, _) =>
            {
                int idx = _retentionCombo.SelectedIndex;
                if (idx >= 0 && idx < RETENTION_PRESETS.Length)
                {
                    _config.RetentionDays = RETENTION_PRESETS[idx].Days;
                    ConfigManager.SaveConfig(_config);
                }
            };

            panel.Controls.Add(_retentionCheck);
            panel.Controls.Add(_retentionCombo);

            // Access-tracking status line. When access times are off (the Windows default),
            // retention falls back to import date — which still works, just doesn't reflect
            // "was this folder opened recently." We tell the user plainly.
            bool accessOn = _isAccessTrackingEnabled();
            _accessStatus = new Label
            {
                Location = new Point(12, 60),
                Size = new Size(420, 36),
                ForeColor = accessOn ? Theme.TEXT_DIM : Theme.RED,
                BackColor = Theme.BG,
                Text = accessOn
                    ? "Access tracking: ON — folders age out by last open."
                    : "Access tracking: OFF — folders age out by import date.\n(Enable for true last-access tracking; needs admin + restart.)"
            };
            panel.Controls.Add(_accessStatus);

            _enableAccessBtn = new Button
            {
                Text = accessOn ? "Access tracking enabled" : "Enable access tracking…",
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Location = new Point(440, 58),
                Size = new Size(105, 28),
                Enabled = !accessOn
            };
            _enableAccessBtn.Click += (_, _) => EnableAccessTracking();
            panel.Controls.Add(_enableAccessBtn);

            _sweepNowBtn = new Button
            {
                Text = "Run sweep now",
                FlatStyle = FlatStyle.Flat,
                BackColor = Theme.BG2,
                ForeColor = Theme.TEXT,
                Location = new Point(12, 104),
                Size = new Size(140, 30)
            };
            _sweepNowBtn.Click += (_, _) => RunSweepNow();
            panel.Controls.Add(_sweepNowBtn);

            var hint = new Label
            {
                Location = new Point(162, 108),
                Size = new Size(380, 24),
                ForeColor = Theme.TEXT_DIM,
                BackColor = Theme.BG,
                Text = "Eligible folders go to the Recycle Bin (recoverable). Today's folder is always exempt."
            };
            panel.Controls.Add(hint);

            // Dock ordering: this panel must sit just above the bottom row. BringToFront puts it
            // at the top of the docked stack, but the bottom row is brought to front AFTER this
            // method returns, so it lands below this panel as intended.
            panel.BringToFront();
        }

        void EnableAccessTracking()
        {
            if (MessageBox.Show(this,
                "Enable Windows access-time tracking?\n\n" +
                "This lets retention consider when folders were last opened, not just imported.\n\n" +
                "Windows will ask for administrator permission, and you'll need to restart your PC\n" +
                "for the change to fully take effect.",
                "Enable access tracking",
                MessageBoxButtons.OKCancel,
                MessageBoxIcon.Information) != DialogResult.OK) return;

            // TryEnable is internally bounded at 30s (it WaitForExits the elevated fsutil). The
            // elevated process shows its own UAC prompt, so calling it directly on the UI thread is
            // correct and no worse than a pointless thread.Join(Infinite) that would freeze the UI
            // for the same duration.
            bool ok = AccessTimeTracker.TryEnable();

            if (ok)
            {
                MessageBox.Show(this,
                    "Access-time tracking has been enabled.\n\nRestart your PC for it to take full effect.",
                    "Enabled", MessageBoxButtons.OK, MessageBoxIcon.Information);
                _accessStatus.Text = "Access tracking: ON (after restart) — folders age out by last open.";
                _accessStatus.ForeColor = Theme.TEXT_DIM;
                _enableAccessBtn.Enabled = false;
                _enableAccessBtn.Text = "Enabled (restart)";
            }
            else
            {
                MessageBox.Show(this,
                    "Couldn't enable access tracking — the admin prompt was cancelled or failed.\n" +
                    "Retention will keep using import date, which still works fine.",
                    "Not enabled", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        void RunSweepNow()
        {
            // Confirm before deleting anything, even to the Recycle Bin. Show the threshold so
            // the user knows exactly what "now" means.
            string age = _retentionCombo.SelectedIndex >= 0
                ? RETENTION_PRESETS[_retentionCombo.SelectedIndex].Label
                : $"{_config.RetentionDays} days";

            if (!_config.RetentionEnabled)
            {
                if (MessageBox.Show(this,
                    $"Retention is currently off.\n\nRun a one-time sweep now anyway, deleting folders older than {age}?",
                    "Run sweep", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
                    return;
            }
            else
            {
                if (MessageBox.Show(this,
                    $"Run a retention sweep now?\n\nFolders older than {age} (by last activity) will be sent to the Recycle Bin.",
                    "Run sweep", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
                    return;
            }

            _sweepNowBtn.Enabled = false;
            _sweepNowBtn.Text = "Sweeping…";
            try
            {
                var (recycled, reclaimed) = _runSweepNow();
                MessageBox.Show(this,
                    recycled > 0
                        ? $"Sweep complete.\n\nRecycled {recycled} folder(s), reclaimed {AutoIngest.Engine.FileSize.Format(reclaimed)}.\nThey're in the Recycle Bin if you need them back."
                        : "Sweep complete. Nothing was eligible for deletion.",
                    "Sweep result", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, $"Sweep failed: {ex.Message}", "Sweep error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                _sweepNowBtn.Enabled = true;
                _sweepNowBtn.Text = "Run sweep now";
            }
        }

        void PopulateDevices()
        {
            _devicesList.BeginUpdate();
            _devicesList.Items.Clear();
            foreach (var d in _registry.All)
            {
                var item = new ListViewItem(d.Name);
                item.SubItems.Add(d.Kind);
                item.SubItems.Add(d.AddedUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm"));
                item.SubItems.Add(TruncateTail(d.Id, 6));
                item.Tag = d.Id;
                item.ForeColor = Theme.TEXT;
                _devicesList.Items.Add(item);
            }
            _devicesList.EndUpdate();
        }

        void PopulateConnected()
        {
            _connectedList.BeginUpdate();
            _connectedList.Items.Clear();
            try
            {
                var connected = _getConnected();
                var registered = new HashSet<string>(
                    _registry.All.Select(d => d.Id),
                    StringComparer.OrdinalIgnoreCase);

                foreach (var dev in connected)
                {
                    if (registered.Contains(dev.Id)) continue;
                    var item = new ListViewItem(dev.DisplayName);
                    item.SubItems.Add(dev.Kind);
                    item.SubItems.Add(dev.Id);
                    item.Tag = dev;
                    item.ForeColor = dev.Kind.Contains("weak", StringComparison.OrdinalIgnoreCase)
                        ? Theme.TEXT_DIM : Theme.TEXT;
                    _connectedList.Items.Add(item);
                }
            }
            catch { /* best-effort refresh */ }
            _connectedList.EndUpdate();
        }

        void RemoveSelected()
        {
            if (_devicesList.SelectedItems.Count == 0) return;
            var item = _devicesList.SelectedItems[0];
            string? id = item.Tag as string;
            if (id == null) return;

            // Confirm — removing a device means it will prompt next time it's plugged in.
            var dev = _registry.Find(id);
            if (dev == null) return;
            if (MessageBox.Show(this,
                $"Remove '{dev.Name}' from registered devices?\n\n" +
                "It will no longer import automatically.",
                "Remove device", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                != DialogResult.Yes) return;

            _registry.Remove(id);
            _registry.Save();
            PopulateDevices();
        }

        void RegisterSelected()
        {
            if (_connectedList.SelectedItems.Count == 0) return;
            var item = _connectedList.SelectedItems[0];
            if (item.Tag is not DeviceIdentity dev) return;

            _registry.Register(dev.Id, dev.DisplayName, dev.Kind);
            _registry.Save();
            PopulateDevices();
            PopulateConnected();
        }

        static string TruncateTail(string s, int n) =>
            string.IsNullOrEmpty(s) || s.Length <= n ? s : s.Substring(s.Length - n);
    }
}
