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

#nullable disable

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language.Syntax.InternalSyntax;

namespace Microsoft.AspNetCore.Razor.Language.Legacy;

internal abstract class LanguageCharacteristics<TTokenizer>
    where TTokenizer : Tokenizer
{
    public abstract string GetSample(SyntaxKind type);
    public abstract TTokenizer CreateTokenizer(ITextDocument source);
    public abstract SyntaxKind FlipBracket(SyntaxKind bracket);
    public abstract SyntaxToken CreateMarkerToken();

    public virtual IEnumerable<SyntaxToken> TokenizeString(string content)
    {
        return TokenizeString(SourceLocation.Zero, content);
    }

    public virtual IEnumerable<SyntaxToken> TokenizeString(SourceLocation start, string input)
    {
        using (var reader = new SeekableTextReader(input, start.FilePath))
        {
            var tok = CreateTokenizer(reader);
            SyntaxToken token;
            while ((token = tok.NextToken()) != null)
            {
                yield return token;
            }
        }
    }

    public virtual bool IsWhitespace(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.Whitespace);
    }

    public virtual bool IsNewLine(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.NewLine);
    }

    public virtual bool IsIdentifier(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.Identifier);
    }

    public virtual bool IsKeyword(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.Keyword);
    }

    public virtual bool IsTransition(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.Transition);
    }

    public virtual bool IsCommentStart(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.CommentStart);
    }

    public virtual bool IsCommentStar(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.CommentStar);
    }

    public virtual bool IsCommentBody(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.CommentBody);
    }

    public virtual bool IsUnknown(SyntaxToken token)
    {
        return IsKnownTokenType(token, KnownTokenType.Unknown);
    }

    public virtual bool IsKnownTokenType(SyntaxToken token, KnownTokenType type)
    {
        return token != null && (token.Kind == GetKnownTokenType(type));
    }

    public virtual (SyntaxToken left, SyntaxToken right) SplitToken(SyntaxToken token, int splitAt, SyntaxKind leftType)
    {
        var left = CreateToken(token.Content.Substring(0, splitAt), leftType, RazorDiagnostic.EmptyArray);

        SyntaxToken right = null;
        if (splitAt < token.Content.Length)
        {
            right = CreateToken(token.Content.Substring(splitAt), token.Kind, token.GetDiagnostics());
        }

        return (left, right);
    }

    public abstract SyntaxKind GetKnownTokenType(KnownTokenType type);

    public virtual bool KnowsTokenType(KnownTokenType type)
    {
        return type == KnownTokenType.Unknown || (GetKnownTokenType(type) != GetKnownTokenType(KnownTokenType.Unknown));
    }

    protected abstract SyntaxToken CreateToken(string content, SyntaxKind type, RazorDiagnostic[] errors);
}
