﻿// 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.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Collections;
using Microsoft.CodeAnalysis.Structure;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.CSharp.Structure
{
    /// <summary>
    /// Adds structure guides for the portions of a #if directive that are active.  The inactive sections already have
    /// structure guides added through <see cref="DisabledTextTriviaStructureProvider"/>.
    /// </summary>
    internal sealed class IfDirectiveTriviaStructureProvider : AbstractSyntaxNodeStructureProvider<IfDirectiveTriviaSyntax>
    {
        protected override void CollectBlockSpans(
            SyntaxToken previousToken,
            IfDirectiveTriviaSyntax node,
            ref TemporaryArray<BlockSpan> spans,
            BlockStructureOptions options,
            CancellationToken cancellationToken)
        {
            var allRelatedDirectives = node.GetRelatedDirectives();
            SourceText? text = null;

            for (int i = 0, n = allRelatedDirectives.Count - 1; i < n; i++)
            {
                var directive = allRelatedDirectives[i];
                if (directive is not BranchingDirectiveTriviaSyntax branchingDirective)
                    continue;

                // if the branch isn't taken, we'll have disabled text.  That's handled by DisabledTextTriviaStructureProvider
                if (!branchingDirective.BranchTaken)
                    continue;

                var nextDirective = allRelatedDirectives[i + 1];
                text ??= node.SyntaxTree.GetText(cancellationToken);

                var startLineNumber = text.Lines.GetLineFromPosition(directive.SpanStart).LineNumber + 1;
                var endLineNumber = text.Lines.GetLineFromPosition(nextDirective.SpanStart).LineNumber - 1;
                if (startLineNumber >= endLineNumber)
                    continue;

                if (startLineNumber >= text.Lines.Count || endLineNumber < 0)
                    continue;

                var startLine = text.Lines[startLineNumber];
                var endLine = text.Lines[endLineNumber];

                var span = TextSpan.FromBounds(startLine.Start, endLine.End);
                spans.Add(new BlockSpan(
                    isCollapsible: true,
                    textSpan: span,
                    type: BlockTypes.PreprocessorRegion,
                    bannerText: CSharpStructureHelpers.Ellipsis,
                    autoCollapse: false));
            }
        }
    }
}
