// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;
using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles;
using Microsoft.CodeAnalysis.NamingStyles;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;

internal class NamingStyleSetting
{
    private NamingStyle[] _allStyles;
    private readonly NamingStyleSettingsUpdater? _settingsUpdater;

    public NamingStyleSetting(
        NamingRule namingRule,
        NamingStyle[] allStyles,
        NamingStyleSettingsUpdater settingsUpdater,
        string? fileName = null)
    {
        Style = namingRule.NamingStyle;
        _allStyles = allStyles;
        Type = namingRule.SymbolSpecification;
        Severity = namingRule.EnforcementLevel;
        _settingsUpdater = settingsUpdater;
        Location = new SettingLocation(fileName is null ? LocationKind.VisualStudio : LocationKind.EditorConfig, fileName);
    }

    private NamingStyleSetting()
    {
        _allStyles = [];
    }

    public event EventHandler<EventArgs>? SettingChanged;

    internal static NamingStyleSetting FromParseResult(NamingStyleOption namingStyleOption)
    {
        return new NamingStyleSetting
        {
            Style = namingStyleOption.NamingScheme.AsNamingStyle(),
            Type = namingStyleOption.ApplicableSymbolInfo.AsSymbolSpecification(),
            Severity = namingStyleOption.Severity.Value,
            Location = new SettingLocation(LocationKind.EditorConfig, namingStyleOption.Section.FilePath)
        };
    }

    internal NamingStyle Style { get; set; }
    internal SymbolSpecification? Type { get; set; }

    public string StyleName => Style.Name;
    public string[] AllStyles => [.. _allStyles.Select(style => style.Name)];
    public string TypeName => Type?.Name ?? string.Empty;
    public ReportDiagnostic Severity { get; private set; }
    public SettingLocation? Location { get; protected set; }

    private void OnSettingChanged((object, object?) setting)
    {
        if (setting is (ReportDiagnostic severity, _))
        {
            Severity = severity;
            SettingChanged?.Invoke(this, EventArgs.Empty);
        }

        if (setting is (NamingStyle style, NamingStyle[] allStyles))
        {
            Style = style;
            _allStyles = allStyles;
            SettingChanged?.Invoke(this, EventArgs.Empty);
        }
    }

    internal void ChangeSeverity(ReportDiagnostic severity)
    {
        if (Location is not null)
        {
            Location = Location with { LocationKind = LocationKind.EditorConfig };
            _settingsUpdater?.QueueUpdate((OnSettingChanged, this), severity);
        }
    }

    internal void ChangeStyle(int selectedIndex)
    {
        if (selectedIndex > -1 && selectedIndex < _allStyles.Length && Location is not null)
        {
            Location = Location with { LocationKind = LocationKind.EditorConfig };
            _settingsUpdater?.QueueUpdate((OnSettingChanged, this), _allStyles[selectedIndex]);
        }
    }
}
