using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace Radzen
{
    /// <summary>
    /// Options for changing the theme.
    /// </summary>
    public class ThemeOptions
    {
        /// <summary>
        /// Specifies the theme.
        /// </summary>
        public string? Theme { get; set; }
        /// <summary>
        /// Specifies if the theme colors should meet WCAG contrast requirements.
        /// </summary>
        public bool? Wcag { get; set; }
        /// <summary>
        /// Specifies if the theme should be right-to-left.
        /// </summary>
        public bool? RightToLeft { get; set; }
        /// <summary>
        /// Specifies if the theme change should trigger the <see cref="ThemeService.ThemeChanged" /> event.
        /// </summary>
        public bool TriggerChange { get; set; }
    }

    /// <summary>
    /// Theme definition.
    /// </summary>
    public class Theme
    {
        /// <summary>
        /// Specifies the user-friendly theme name e.g. Material3.
        /// </summary>
        public string? Text { get; set; }
        /// <summary>
        /// Specifies the theme value e.g. material3.
        /// </summary>
        public string? Value { get; set; }
        /// <summary>
        /// Specifies the primary color.
        /// </summary>
        public string? Primary { get; set; }
        /// <summary>
        /// Specifies the secondary color.
        /// </summary>
        public string? Secondary { get; set; }
        /// <summary>
        /// Specifies the base color.
        /// </summary>
        public string? Base { get; set; }
        /// <summary>
        /// Specifies the content color.
        /// </summary>
        public string? Content { get; set; }
        /// <summary>
        /// Specifies the title text color.
        /// </summary>
        public string? TitleText { get; set; }
        /// <summary>
        /// Specifies the content text color.
        /// </summary>
        public string? ContentText { get; set; }
        /// <summary>
        /// Specifies the selection color.
        /// </summary>
        public string? Selection { get; set; }
        /// <summary>
        /// Specifies the selection text color.
        /// </summary>
        public string? SelectionText { get; set; }
        /// <summary>
        /// Specifies the button radius.
        /// </summary>
        public string? ButtonRadius { get; set; }
        /// <summary>
        /// Specifies the card radius.
        /// </summary>
        public string? CardRadius { get; set; }
        /// <summary>
        /// Specifies the series A color.
        /// </summary>
        public string? SeriesA { get; set; }
        /// <summary>
        /// Specifies the series B color.
        /// </summary>
        public string? SeriesB { get; set; }
        /// <summary>
        /// Specifies the series C color.
        /// </summary>
        public string? SeriesC { get; set; }
        /// <summary>
        /// Specifies if the theme is premium.
        /// </summary>
        public bool Premium { get; set; }
    }

    /// <summary>
    /// Predefined themes.
    /// </summary>
    public static class Themes
    {
        /// <summary>
        /// Predefined themes.
        /// </summary>
        public static readonly Theme[] All = [
            new Theme {
                Text = "Material 3",
                Value = "material3",
                Premium = true,
                Primary = "#3481e5",
                Secondary = "#5b6471",
                Base = "#ffffff",
                Selection = "rgba(0, 107, 255, 0.13)",
                SelectionText = "#1b1d20",
                Content = "#f8f7ff",
                TitleText = "#1b1d20",
                ContentText = "#5b6471",
                ButtonRadius = "4",
                CardRadius = "8",
                SeriesA = "#75abf0",
                SeriesB = "#9c75f0",
                SeriesC = "#f075e8"
            },
            new Theme {
                Text = "Material 3 Dark",
                Value = "material3-dark",
                Premium = true,
                Primary = "#94c1ff",
                Secondary = "#c2cbdc",
                Base = "#121418",
                Selection = "rgba(144, 181, 255, 0.28)",
                SelectionText = "#c2cbdc",
                Content = "#1b1d20",
                TitleText = "#e0e0e9",
                ContentText = "#e0e0e9",
                ButtonRadius = "4",
                CardRadius = "8",
                SeriesA = "#3d71b8",
                SeriesB = "#663db8",
                SeriesC = "#b83dae"
            },
            new Theme {
                Text = "Material 3 Expressive",
                Value = "material3expressive",
                Premium = true,
                Primary = "#5f33d6",
                Secondary = "#573d8f",
                Base = "#ffffff",
                Selection = "rgba(69, 0, 255, 0.13)",
                SelectionText = "#21005d",
                Content = "#f9f8fc",
                TitleText = "#1c1b20",
                ContentText = "#77747e",
                ButtonRadius = "4",
                CardRadius = "8",
                SeriesA = "#9675f0",
                SeriesB = "#f075ed",
                SeriesC = "#f07591"
            },
            new Theme {
                Text = "Material 3 Expressive Dark",
                Value = "material3expressive-dark",
                Premium = true,
                Primary = "#cdbcff",
                Secondary = "#c8b9e5",
                Base = "#141218",
                Selection = "rgba(205, 188, 255, 0.24)",
                SelectionText = "#c8b9e5",
                Content = "#1c1b20",
                TitleText = "#e2e0e9",
                ContentText = "#e2e0e9",
                ButtonRadius = "4",
                CardRadius = "8",
                SeriesA = "#5c3db8",
                SeriesB = "#b83db7",
                SeriesC = "#b83d5b"
            },
            new Theme {
                Text = "Fluent",
                Value = "fluent",
                Premium = true,
                Primary = "#0078d4",
                Secondary = "#8a8886",
                Base = "#f5f5f5",
                Selection = "#0078d4",
                SelectionText = "#ffffff",
                Content = "white",
                TitleText = "black",
                ContentText = "#605e5c",
                ButtonRadius = "1",
                CardRadius = "2",
                SeriesA = "#0078d4",
                SeriesB = "#b4a0ff",
                SeriesC = "#d83b01"
            },
            new Theme {
                Text = "Fluent Dark",
                Value = "fluent-dark",
                Premium = true,
                Primary = "#479ef5",
                Secondary = "#5c5c5c",
                Base = "#292929",
                Selection = "#479ef5",
                SelectionText = "#0a0a0a",
                Content = "#333333",
                TitleText = "#ffffff",
                ContentText = "#d6d6d6",
                ButtonRadius = "1",
                CardRadius = "2",
                SeriesA = "#0078d4",
                SeriesB = "#b4a0ff",
                SeriesC = "#d83b01"
            },
            new Theme {
                Text = "Material",
                Value = "material",
                Primary = "#4340d2",
                Secondary = "#e31c65",
                Base = "#f5f5f5",
                Selection = "rgba(67, 64, 210, 0.12)",
                SelectionText = "#4340d2",
                Content = "#ffffff",
                TitleText = "#212121",
                ContentText = "#bdbdbd",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#3700b3",
                SeriesB = "#ba68c8",
                SeriesC = "#f06292"
            },
            new Theme {
                Text = "Material Dark",
                Value = "material-dark",
                Primary = "#bb86fc",
                Secondary = "#01a299",
                Base = "#121212",
                Selection = "rgba(187, 134, 252, 0.12)",
                SelectionText = "#bb86fc",
                Content = "#252525",
                TitleText = "#ffffff",
                ContentText = "#a0a0a0",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#3700b3",
                SeriesB = "#ba68c8",
                SeriesC = "#f06292"
            },
            new Theme {
                Text = "Standard",
                Value = "standard",
                Primary = "#1151f3",
                Secondary = "rgba(17, 81, 243, 0.16)",
                Base = "#f4f5f9",
                Selection = "rgba(114, 152, 248, 0.16)",
                SelectionText = "#1151f3",
                Content = "#ffffff",
                TitleText = "#262526",
                ContentText = "#afafb2",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            },
            new Theme {
                Text = "Standard Dark",
                Value = "standard-dark",
                Primary = "#3871ff",
                Secondary = "#2a3c68",
                Base = "#19191a",
                Selection = "rgba(56, 113, 255, 0.2)",
                SelectionText = "#88aaff",
                Content = "#242527",
                TitleText = "#ffffff",
                ContentText = "#eaebec",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            },
            new Theme {
                Text = "Default",
                Value = "default",
                Primary = "#ff6d41",
                Secondary = "#35a0d7",
                Base = "#f6f7fa",
                Selection = "#3193c6",
                SelectionText = "#ffffff",
                Content = "#ffffff",
                TitleText = "#28363c",
                ContentText = "#95a4a8",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#0479cc",
                SeriesB = "#68d5c8",
                SeriesC = "#ff6d41"
            },
            new Theme {
                Text = "Dark",
                Value="dark",
                Primary = "#ff6d41",
                Secondary = "#35a0d7",
                Base = "#28363c",
                Selection = "#3692c4",
                SelectionText = "#ffffff",
                Content = "#38474e",
                TitleText = "#ffffff",
                ContentText = "#a8b4b8",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#0479cc",
                SeriesB = "#68d5c8",
                SeriesC = "#ff6d41"
            },
            new Theme {
                Text = "Humanistic",
                Value = "humanistic",
                Primary = "#d64d42",
                Secondary = "#3ba5fc",
                Base = "#f3f5f7",
                Selection = "#3698e8",
                SelectionText = "#ffffff",
                Content = "#ffffff",
                TitleText = "#2b3a50",
                ContentText = "#7293b6",
                ButtonRadius = "0",
                CardRadius = "0",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            },
            new Theme {
                Text = "Humanistic Dark",
                Value = "humanistic-dark",
                Primary = "#d64d42",
                Secondary = "#3ba5fc",
                Base = "#2b3a50",
                Selection = "#3698e8",
                SelectionText = "#ffffff",
                Content = "#30445f",
                TitleText = "#ffffff",
                ContentText = "#d9e1ea",
                ButtonRadius = "0",
                CardRadius = "0",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            },
            new Theme {
                Text = "Software",
                Value = "software",
                Primary = "#598087",
                Secondary = "#80a4ab",
                Base = "#f6f7fa",
                Selection = "#76979d",
                SelectionText = "#ffffff",
                Content = "#ffffff",
                TitleText = "#28363c",
                ContentText = "#95a4a8",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            },
            new Theme {
                Text = "Software Dark",
                Value = "software-dark",
                Primary = "#598087",
                Secondary = "#80a4ab",
                Base = "#28363c",
                Selection = "#76979d",
                SelectionText = "#ffffff",
                Content = "#3a474d",
                TitleText = "#ffffff",
                ContentText = "#f5f8f9",
                ButtonRadius = "2",
                CardRadius = "4",
                SeriesA = "#376df5",
                SeriesB = "#64dfdf",
                SeriesC = "#f68769"
            }
        ];

        /// <summary>
        /// Free themes.
        /// </summary>
        public static IEnumerable<Theme> Free => All.Where(theme => !theme.Premium);

        /// <summary>
        /// Premium themes.
        /// </summary>
        public static IEnumerable<Theme> Premium => All.Where(theme => theme.Premium);
    }

    /// <summary>
    /// Service for theme registration and management.
    /// </summary>
    public class ThemeService(IJSRuntime jsRuntime, IServiceProvider serviceProvider)
    {

        private string? theme;
        /// <summary>
        /// Gets the current theme.
        /// </summary>
        public string? Theme
        {
            [UnconditionalSuppressMessage(TrimMessages.Trimming, TrimMessages.IL2026, Justification = TrimMessages.ThemeTypePreserved)]
            get
            {
                if (theme == null)
                {
                    var persistentComponentState = serviceProvider.GetService<PersistentComponentState>();

                    if (persistentComponentState?.TryTakeFromJson(nameof(Theme), out string? persistedTheme) == true && persistedTheme != null)
                    {
                        theme = persistedTheme;
                    }
                }
                return theme;
            }

            private set => theme = value;
        }

        /// <summary>
        /// Specify if the theme colors should meet WCAG contrast requirements.
        /// </summary>
        public bool? Wcag { get; private set; }

        /// <summary>
        /// Specify if the theme should be right-to-left.
        /// </summary>
        public bool? RightToLeft { get; private set; }

        /// <summary>
        /// Custom css path. If set, it overwrites the default path.
        /// </summary>
        public string? CssPath { get; private set; }

        /// <summary>
        /// Raised when the theme changes.
        /// </summary>
        public event Action? ThemeChanged;

        /// <summary>
        /// Changes the current theme.
        /// </summary>
        public void SetTheme(string theme, bool triggerChange = true)
        {
            SetTheme(new ThemeOptions
            {
                Theme = theme,
                Wcag = Wcag,
                RightToLeft = RightToLeft,
                TriggerChange = triggerChange
            });
        }

        /// <summary>
        /// Changes the current theme with additional options.
        /// </summary>
        public void SetTheme(ThemeOptions options)
        {
            ArgumentNullException.ThrowIfNull(options);

            var requiresChange = false;

            if (Theme != options.Theme)
            {
                Theme = options.Theme;
                requiresChange = true;
            }

            if (Wcag != options.Wcag)
            {
                Wcag = options.Wcag;
                requiresChange = true;
            }

            if (RightToLeft != options.RightToLeft)
            {
                RightToLeft = options.RightToLeft;
                requiresChange = true;
            }

            if (requiresChange && options.TriggerChange)
            {
                ThemeChanged?.Invoke();

                try
                {
                    if (Href != null)
                    {
                        jsRuntime.InvokeVoid("Radzen.setTheme", Href, Wcag == true ? WcagHref : null!);
                    }
                }
                catch (Exception)
                {
                }
            }
        }
        [UnconditionalSuppressMessage(TrimMessages.Trimming, TrimMessages.IL2026, Justification = TrimMessages.AssemblyMetadataPreserved)]
        private static readonly string? Version = typeof(ThemeService).Assembly.GetName().Version?.ToString();

        internal string Href => $"{Path}/{Theme}-base.css?v={Version}";

        internal string WcagHref => $"{Path}/{Theme}-wcag.css?v={Version}";

        private string Path => Embedded
            ? $"_content/Radzen.Blazor/css"
            : !string.IsNullOrEmpty(CssPath)
                ? CssPath
                : "css";

        internal bool Embedded => Theme switch
        {
            "material" => true,
            "material-dark" => true,
            "standard" => true,
            "standard-dark" => true,
            "humanistic" => true,
            "humanistic-dark" => true,
            "software" => true,
            "software-dark" => true,
            "default" => true,
            "dark" => true,
            _ => false
        };

        /// <summary>
        /// Enables or disables WCAG contrast requirements.
        /// </summary>
        public void SetWcag(bool wcag)
        {
            SetTheme(new ThemeOptions
            {
                Theme = Theme,
                Wcag = wcag,
                RightToLeft = RightToLeft,
                TriggerChange = true
            });
        }

        /// <summary>
        /// Specifies if the theme should be right-to-left.
        /// </summary>
        public void SetRightToLeft(bool rightToLeft)
        {
            SetTheme(new ThemeOptions
            {
                Theme = Theme,
                Wcag = Wcag,
                RightToLeft = rightToLeft,
                TriggerChange = true
            });
        }

        /// <summary>
        /// Sets a specific css path to the theme service.
        /// </summary>
        /// <param name="cssPath">New css path to look for themes.</param>
        public void SetCssPath(string? cssPath)
        {
            CssPath = cssPath;
        }
    }
}