using System.IO;
using System.Text.Json;

namespace DragonISO.App.Services;

/// <summary>
/// Persistent UI-side toggles that don't belong in <see cref="DragonISO.Engine.Persistence.ConfigStore"/>
/// (which is the engine's domain model â€” framerate, NDI groups, ISO assignments).
///
/// Each toggle is a property on a single record persisted as JSON at
/// <c>%LOCALAPPDATA%\Dragon-ISO\ui-prefs.json</c>. Defaults match the original
/// in-memory behavior: HideLocalSelf=true (filter the operator's own preview
/// out of the participants list) and AutoDisableOnDeparture=false (a participant
/// going offline doesn't tear down their pipeline by default â€” operators
/// usually want to keep the routing in case they reconnect).
///
/// Centralizing these here means the settings VM doesn't have to plumb
/// individual Set methods to dedicated services for every new bool.
/// </summary>
public static class UIPreferences
{
    private static readonly object _gate = new();

    private static string PrefsPath =>
        Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "Dragon-ISO", "ui-prefs.json");

    /// <summary>
    /// Sort modes for the participants DataGrid. <see cref="JoinOrder"/> is the default
    /// and matches the engine's discovery order (operators with custom Stream Deck
    /// layouts sometimes prefer Alphabetical for stability across meetings).
    /// <see cref="LoudestFirst"/> resorts at the 1Hz stats tick so the active
    /// speaker bubbles to the top â€” useful for operators reacting to who's talking.
    /// </summary>
    public enum SortMode { JoinOrder, Alphabetical, OnlineFirst, LoudestFirst }

    /// <summary>The on-disk shape. New fields added here become opt-in for older files via default values.</summary>
    public sealed record Prefs(
        bool HideLocalSelf = true,
        bool AutoDisableOnDeparture = false,
        SortMode ParticipantSort = SortMode.JoinOrder,
        bool MinimizeToTray = false,
        bool ControlSurfaceLanReachable = false,
        // Phase E.1 / E.2 quality-of-life. With both true, the operator launches
        // Dragon-ISO and never sees the Teams UI â€” Teams auto-starts in the
        // background and its windows are auto-hidden as soon as they materialize.
        // All control happens via the IN-CALL bar + participants DataGrid.
        bool LaunchTeamsOnStartup = false,
        bool AutoHideTeamsWindows = false,
        // Experimental Phase E.4. SetParent-reparents Teams' main window
        // into a Dragon-ISO-owned host. WebView2 in modern Teams can render
        // weirdly after reparent; if so the operator unticks and falls
        // back to auto-hide mode. Off by default.
        bool EmbedTeamsWindow = false,
        // Theme preference for the v2 redesign. One of "System" (follow
        // Windows app-mode), "Dark", or "Light". ThemeManager hydrates
        // from this on startup and persists back here on toggle. Default
        // "System" matches DESIGN.md's "Follow Windows" choice â€” the
        // operator who doesn't care gets whatever Windows is set to.
        string Theme = "System",
        // REST + WebSocket control surface auto-start. When true, the
        // server starts on app launch instead of waiting for the operator
        // to click the toggle in settings each session. The desktop GUI's
        // settings checkbox writes here and re-reads on launch.
        bool ControlSurfaceEnabled = false);

    /// <summary>Update just the Theme field without touching other prefs.</summary>
    public static void SetTheme(string theme)
    {
        var current = Load();
        Save(current with { Theme = theme });
    }

    public static Prefs Load()
    {
        try
        {
            if (!File.Exists(PrefsPath)) return new Prefs();
            var json = File.ReadAllText(PrefsPath);
            return JsonSerializer.Deserialize<Prefs>(json) ?? new Prefs();
        }
        catch
        {
            return new Prefs();
        }
    }

    public static void Save(Prefs prefs)
    {
        try
        {
            lock (_gate)
            {
                var dir = Path.GetDirectoryName(PrefsPath);
                if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
                var json = JsonSerializer.Serialize(prefs, new JsonSerializerOptions { WriteIndented = true });
                File.WriteAllText(PrefsPath, json);
            }
        }
        catch
        {
            // Disk full / permission denied â€” in-memory state still holds for this session.
        }
    }
}
