/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file for additional information.
 * The ASF licenses this file under the Apache License, Version 2.0.
 */

using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Lucene.Net.CodeAnalysis.Dev.Utility;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;

namespace Lucene.Net.CodeAnalysis.Dev.CodeFixes.LuceneDev6xxx
{
    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(LuceneDev6001_6002_StringComparisonCodeFixProvider)), Shared]
    public sealed class LuceneDev6001_6002_StringComparisonCodeFixProvider : CodeFixProvider
    {
        private const string Ordinal = "Ordinal";
        private const string OrdinalIgnoreCase = "OrdinalIgnoreCase";
        private const string TitleOrdinal = "Use StringComparison.Ordinal";
        private const string TitleOrdinalIgnoreCase = "Use StringComparison.OrdinalIgnoreCase";

        public override ImmutableArray<string> FixableDiagnosticIds =>
            ImmutableArray.Create(
                Descriptors.LuceneDev6001_MissingStringComparison.Id,
                Descriptors.LuceneDev6002_InvalidStringComparison.Id);

        public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

        /// <summary>
        /// Registers available code fixes for all diagnostics in the context.
        /// </summary>
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            if (root == null) return;

            // Iterate over ALL diagnostics in the context to ensure all issues are offered a fix.
            foreach (var diagnostic in context.Diagnostics)
            {
                var invocation = root.FindToken(diagnostic.Location.SourceSpan.Start)
                                     .Parent?
                                     .AncestorsAndSelf()
                                     .OfType<InvocationExpressionSyntax>()
                                     .FirstOrDefault();
                if (invocation == null) continue;

                var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
                if (semanticModel == null) continue;

                // Skip char literals and single-character string literals when safe (LuceneDev6005 handles conversion).
                var firstArgExpr = invocation.ArgumentList.Arguments.FirstOrDefault()?.Expression;
                if (firstArgExpr is LiteralExpressionSyntax lit)
                {
                    if (lit.IsKind(SyntaxKind.CharacterLiteralExpression))
                        continue;

                    if (lit.IsKind(SyntaxKind.StringLiteralExpression) && lit.Token.ValueText.Length == 1)
                    {
                        bool hasStringComparisonArg = invocation.ArgumentList.Arguments.Any(arg =>
                            (semanticModel.GetTypeInfo(arg.Expression).Type is INamedTypeSymbol t &&
                                t.ToDisplayString() == "System.StringComparison")
                            || (semanticModel.GetSymbolInfo(arg.Expression).Symbol is IFieldSymbol f &&
                                f.ContainingType?.ToDisplayString() == "System.StringComparison"));

                        if (!hasStringComparisonArg)
                            continue;
                    }
                }

                // --- Fix Registration Logic ---

                if (diagnostic.Id == Descriptors.LuceneDev6001_MissingStringComparison.Id)
                {
                    // Case 1: Argument is missing. Only offer Ordinal as the safe, conservative default.
                    RegisterFix(context, invocation, Ordinal, TitleOrdinal, diagnostic);
                }
                else if (diagnostic.Id == Descriptors.LuceneDev6002_InvalidStringComparison.Id)
                {
                    // Case 2: Invalid argument is present. Determine the best replacement.
                    if (TryDetermineReplacement(invocation, semanticModel, out string? targetComparison))
                    {
                        var title = (targetComparison!) == Ordinal ? TitleOrdinal : TitleOrdinalIgnoreCase;
                        RegisterFix(context, invocation, targetComparison!, title, diagnostic);
                    }
                    // If TryDetermineReplacement returns false, the argument is an invalid non-constant
                    // expression (e.g., a variable). We skip the fix to avoid arbitrary changes.
                }
            }
        }

        private static void RegisterFix(
            CodeFixContext context,
            InvocationExpressionSyntax invocation,
            string comparisonMember,
            string title,
            Diagnostic diagnostic)
        {
            context.RegisterCodeFix(CodeAction.Create(
                title: title,
                createChangedDocument: c => FixInvocationAsync(context.Document, invocation, comparisonMember, c),
                equivalenceKey: title),
                diagnostic);
        }

        /// <summary>
        /// Determines the appropriate ordinal replacement (Ordinal or OrdinalIgnoreCase)
        /// for an existing culture-sensitive StringComparison argument.
        /// Only operates on constant argument values.
        /// </summary>
        /// <returns>True if a valid replacement was determined, false otherwise (e.g., if argument is non-constant).</returns>
        private static bool TryDetermineReplacement(InvocationExpressionSyntax invocation, SemanticModel semanticModel, out string? targetComparison)
        {
            targetComparison = null;
            var stringComparisonType = semanticModel.Compilation.GetTypeByMetadataName("System.StringComparison");
            var existingArg = invocation.ArgumentList.Arguments.FirstOrDefault(arg =>
                SymbolEqualityComparer.Default.Equals(
                    semanticModel.GetTypeInfo(arg.Expression).Type, stringComparisonType));

            if (existingArg != null)
            {
                var constVal = semanticModel.GetConstantValue(existingArg.Expression);
                if (constVal.HasValue && constVal.Value is int intVal)
                {
                    // Map original comparison to corresponding ordinal variant for constant values
                    switch ((System.StringComparison)intVal)
                    {
                        case System.StringComparison.CurrentCulture:
                        case System.StringComparison.InvariantCulture:
                            targetComparison = Ordinal;
                            return true;
                        case System.StringComparison.CurrentCultureIgnoreCase:
                        case System.StringComparison.InvariantCultureIgnoreCase:
                            targetComparison = OrdinalIgnoreCase;
                            return true;
                        case System.StringComparison.Ordinal:
                        case System.StringComparison.OrdinalIgnoreCase:
                            return false; // Already correct
                    }
                }
                // Argument exists, but is not a constant value (e.g., a variable). We skip the fix.
                return false;
            }

            // Should not be called for missing arguments by the caller.
            return false;
        }

        /// <summary>
        /// Creates the new document by either replacing an existing StringComparison argument
        /// or adding a new one, based on the fix action.
        /// </summary>
        private static async Task<Document> FixInvocationAsync(Document document, InvocationExpressionSyntax invocation, string comparisonMember, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            if (root == null) return document;

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
            var stringComparisonType = semanticModel?.Compilation.GetTypeByMetadataName("System.StringComparison");

            // 1. Create the new StringComparison argument expression
            var stringComparisonExpr = SyntaxFactory.MemberAccessExpression(
                SyntaxKind.SimpleMemberAccessExpression,
                SyntaxFactory.IdentifierName("StringComparison"),
                SyntaxFactory.IdentifierName(comparisonMember));

            var newArg = SyntaxFactory.Argument(stringComparisonExpr);

            // 2. Find existing argument for replacement/addition check
            var existingArg = invocation.ArgumentList.Arguments.FirstOrDefault(arg =>
                semanticModel != null &&
                SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeInfo(arg.Expression).Type, stringComparisonType));

            // 3. Perform the syntax replacement/addition
            InvocationExpressionSyntax newInvocation;
            if (existingArg != null)
            {
                // Argument exists (Replacement case: InvalidComparison)
                // Preserve leading/trailing trivia (spaces/comma) from the expression being replaced
                var newExprWithTrivia = stringComparisonExpr
                    .WithLeadingTrivia(existingArg.Expression.GetLeadingTrivia())
                    .WithTrailingTrivia(existingArg.Expression.GetTrailingTrivia());

                var newArgWithTrivia = existingArg.WithExpression(newExprWithTrivia);

                newInvocation = invocation.ReplaceNode(existingArg, newArgWithTrivia);
            }
            else
            {
                // Argument is missing (Addition case: MissingComparison)
                // Use AddArguments, relying on Roslyn to correctly handle comma/spacing trivia.
                newInvocation = invocation.WithArgumentList(
                    invocation.ArgumentList.AddArguments(newArg)
                );
            }

            // 4. Update the document root (Ensure using statement is present and replace invocation)
            var newRoot = EnsureSystemUsing(root).ReplaceNode(invocation, newInvocation);
            return document.WithSyntaxRoot(newRoot);
        }

        /// <summary>
        /// Ensures a 'using System;' directive is present in the document.
        /// </summary>
        private static SyntaxNode EnsureSystemUsing(SyntaxNode root)
        {
            if (root is CompilationUnitSyntax compilationUnit)
            {
                var hasSystemUsing = compilationUnit.Usings.Any(u =>
                    u.Name is IdentifierNameSyntax id && id.Identifier.ValueText == "System");

                if (!hasSystemUsing)
                {
                    var systemUsing = SyntaxFactory.UsingDirective(SyntaxFactory.IdentifierName("System"))
                                                   .WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed);
                    return compilationUnit.AddUsings(systemUsing);
                }
            }

            return root;
        }
    }
}
