// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using SkiaSharp;

namespace Microsoft.Maui.Platform.Linux.Services;

/// <summary>
/// Provides high contrast mode detection and theme support for accessibility.
/// </summary>
public class HighContrastService
{
    private bool _isHighContrastEnabled;
    private HighContrastTheme _currentTheme = HighContrastTheme.None;
    private bool _initialized;

    /// <summary>
    /// Gets whether high contrast mode is enabled.
    /// </summary>
    public bool IsHighContrastEnabled => _isHighContrastEnabled;

    /// <summary>
    /// Gets the current high contrast theme.
    /// </summary>
    public HighContrastTheme CurrentTheme => _currentTheme;

    /// <summary>
    /// Event raised when high contrast mode changes.
    /// </summary>
    public event EventHandler<HighContrastChangedEventArgs>? HighContrastChanged;

    /// <summary>
    /// Initializes the high contrast service.
    /// </summary>
    public void Initialize()
    {
        if (_initialized) return;
        _initialized = true;

        DetectHighContrast();
    }

    /// <summary>
    /// Detects current high contrast mode settings.
    /// </summary>
    public void DetectHighContrast()
    {
        bool isEnabled = false;
        var theme = HighContrastTheme.None;

        // Try GNOME settings
        if (TryGetGnomeHighContrast(out bool gnomeEnabled, out string? gnomeTheme))
        {
            isEnabled = gnomeEnabled;
            if (gnomeEnabled)
            {
                theme = ParseThemeName(gnomeTheme);
            }
        }
        // Try KDE settings
        else if (TryGetKdeHighContrast(out bool kdeEnabled, out string? kdeTheme))
        {
            isEnabled = kdeEnabled;
            if (kdeEnabled)
            {
                theme = ParseThemeName(kdeTheme);
            }
        }
        // Try GTK settings
        else if (TryGetGtkHighContrast(out bool gtkEnabled, out string? gtkTheme))
        {
            isEnabled = gtkEnabled;
            if (gtkEnabled)
            {
                theme = ParseThemeName(gtkTheme);
            }
        }
        // Check environment variables
        else if (TryGetEnvironmentHighContrast(out bool envEnabled))
        {
            isEnabled = envEnabled;
            theme = HighContrastTheme.WhiteOnBlack; // Default
        }

        UpdateHighContrast(isEnabled, theme);
    }

    private void UpdateHighContrast(bool isEnabled, HighContrastTheme theme)
    {
        if (_isHighContrastEnabled != isEnabled || _currentTheme != theme)
        {
            _isHighContrastEnabled = isEnabled;
            _currentTheme = theme;
            HighContrastChanged?.Invoke(this, new HighContrastChangedEventArgs(isEnabled, theme));
        }
    }

    private static bool TryGetGnomeHighContrast(out bool isEnabled, out string? themeName)
    {
        isEnabled = false;
        themeName = null;

        try
        {
            // Check if high contrast is enabled via gsettings
            var result = RunCommand("gsettings", "get org.gnome.desktop.a11y.interface high-contrast");
            if (!string.IsNullOrEmpty(result))
            {
                isEnabled = result.Trim().ToLower() == "true";
            }

            // Get the current GTK theme
            result = RunCommand("gsettings", "get org.gnome.desktop.interface gtk-theme");
            if (!string.IsNullOrEmpty(result))
            {
                themeName = result.Trim().Trim('\'');

                // Check if theme name indicates high contrast
                if (!isEnabled && themeName != null)
                {
                    var lowerTheme = themeName.ToLower();
                    isEnabled = lowerTheme.Contains("highcontrast") ||
                                lowerTheme.Contains("high-contrast") ||
                                lowerTheme.Contains("hc");
                }
            }

            return true;
        }
        catch
        {
            return false;
        }
    }

    private static bool TryGetKdeHighContrast(out bool isEnabled, out string? themeName)
    {
        isEnabled = false;
        themeName = null;

        try
        {
            // Check kdeglobals for color scheme
            var configPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                ".config", "kdeglobals");

            if (!File.Exists(configPath)) return false;

            var lines = File.ReadAllLines(configPath);
            foreach (var line in lines)
            {
                if (line.StartsWith("ColorScheme="))
                {
                    themeName = line.Substring("ColorScheme=".Length);
                    var lowerTheme = themeName.ToLower();
                    isEnabled = lowerTheme.Contains("highcontrast") ||
                                lowerTheme.Contains("high-contrast") ||
                                lowerTheme.Contains("breeze-high-contrast");
                    return true;
                }
            }

            return false;
        }
        catch
        {
            return false;
        }
    }

    private static bool TryGetGtkHighContrast(out bool isEnabled, out string? themeName)
    {
        isEnabled = false;
        themeName = null;

        try
        {
            // Check GTK settings.ini
            var gtkConfigPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                ".config", "gtk-3.0", "settings.ini");

            if (!File.Exists(gtkConfigPath))
            {
                gtkConfigPath = Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                    ".config", "gtk-4.0", "settings.ini");
            }

            if (!File.Exists(gtkConfigPath)) return false;

            var lines = File.ReadAllLines(gtkConfigPath);
            foreach (var line in lines)
            {
                if (line.StartsWith("gtk-theme-name="))
                {
                    themeName = line.Substring("gtk-theme-name=".Length);
                    var lowerTheme = themeName.ToLower();
                    isEnabled = lowerTheme.Contains("highcontrast") ||
                                lowerTheme.Contains("high-contrast");
                    return true;
                }
            }

            return false;
        }
        catch
        {
            return false;
        }
    }

    private static bool TryGetEnvironmentHighContrast(out bool isEnabled)
    {
        isEnabled = false;

        // Check GTK_THEME environment variable
        var gtkTheme = Environment.GetEnvironmentVariable("GTK_THEME");
        if (!string.IsNullOrEmpty(gtkTheme))
        {
            var lower = gtkTheme.ToLower();
            isEnabled = lower.Contains("highcontrast") || lower.Contains("high-contrast");
            if (isEnabled) return true;
        }

        // Check accessibility-related env vars
        var forceA11y = Environment.GetEnvironmentVariable("GTK_A11Y");
        if (forceA11y?.ToLower() == "atspi" || forceA11y == "1")
        {
            // A11y is forced, but doesn't necessarily mean high contrast
        }

        return isEnabled;
    }

    private static HighContrastTheme ParseThemeName(string? themeName)
    {
        if (string.IsNullOrEmpty(themeName))
            return HighContrastTheme.WhiteOnBlack;

        var lower = themeName.ToLower();

        if (lower.Contains("inverse") || lower.Contains("dark") || lower.Contains("white-on-black"))
            return HighContrastTheme.WhiteOnBlack;

        if (lower.Contains("light") || lower.Contains("black-on-white"))
            return HighContrastTheme.BlackOnWhite;

        // Default to white on black (more common high contrast choice)
        return HighContrastTheme.WhiteOnBlack;
    }

    /// <summary>
    /// Gets the appropriate colors for the current high contrast theme.
    /// </summary>
    public HighContrastColors GetColors()
    {
        return _currentTheme switch
        {
            HighContrastTheme.WhiteOnBlack => new HighContrastColors
            {
                Background = SKColors.Black,
                Foreground = SKColors.White,
                Accent = new SKColor(0, 255, 255), // Cyan
                Border = SKColors.White,
                Error = new SKColor(255, 100, 100),
                Success = new SKColor(100, 255, 100),
                Warning = SKColors.Yellow,
                Link = new SKColor(100, 200, 255),
                LinkVisited = new SKColor(200, 150, 255),
                Selection = new SKColor(0, 120, 215),
                SelectionText = SKColors.White,
                DisabledText = new SKColor(160, 160, 160),
                DisabledBackground = new SKColor(40, 40, 40)
            },
            HighContrastTheme.BlackOnWhite => new HighContrastColors
            {
                Background = SKColors.White,
                Foreground = SKColors.Black,
                Accent = new SKColor(0, 0, 200), // Dark blue
                Border = SKColors.Black,
                Error = new SKColor(180, 0, 0),
                Success = new SKColor(0, 130, 0),
                Warning = new SKColor(180, 120, 0),
                Link = new SKColor(0, 0, 180),
                LinkVisited = new SKColor(80, 0, 120),
                Selection = new SKColor(0, 120, 215),
                SelectionText = SKColors.White,
                DisabledText = new SKColor(100, 100, 100),
                DisabledBackground = new SKColor(220, 220, 220)
            },
            _ => GetDefaultColors()
        };
    }

    private static HighContrastColors GetDefaultColors()
    {
        return new HighContrastColors
        {
            Background = SKColors.White,
            Foreground = new SKColor(33, 33, 33),
            Accent = new SKColor(33, 150, 243),
            Border = new SKColor(200, 200, 200),
            Error = new SKColor(244, 67, 54),
            Success = new SKColor(76, 175, 80),
            Warning = new SKColor(255, 152, 0),
            Link = new SKColor(33, 150, 243),
            LinkVisited = new SKColor(156, 39, 176),
            Selection = new SKColor(33, 150, 243),
            SelectionText = SKColors.White,
            DisabledText = new SKColor(158, 158, 158),
            DisabledBackground = new SKColor(238, 238, 238)
        };
    }

    /// <summary>
    /// Forces a specific high contrast mode (for testing or user preference override).
    /// </summary>
    public void ForceHighContrast(bool enabled, HighContrastTheme theme = HighContrastTheme.WhiteOnBlack)
    {
        UpdateHighContrast(enabled, theme);
    }

    private static string? RunCommand(string command, string arguments)
    {
        try
        {
            using var process = new System.Diagnostics.Process();
            process.StartInfo = new System.Diagnostics.ProcessStartInfo
            {
                FileName = command,
                Arguments = arguments,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };

            process.Start();
            var output = process.StandardOutput.ReadToEnd();
            process.WaitForExit(1000);
            return output;
        }
        catch
        {
            return null;
        }
    }
}
