using NubLang.Diagnostics;

namespace NubLang.Syntax;

public abstract record Token(SourceSpan Span);

public record IdentifierToken(SourceSpan Span, string Value) : Token(Span)
{
    public override string ToString()
    {
        return Value;
    }
}

public record IntLiteralToken(SourceSpan Span, string Value, int Base) : Token(Span)
{
    public ulong AsU64 => Convert.ToUInt64(Value, Base);
    public long AsI64 => Convert.ToInt64(Value, Base);
    public uint AsU32 => Convert.ToUInt32(Value, Base);
    public int AsI32 => Convert.ToInt32(Value, Base);
    public ushort AsU16 => Convert.ToUInt16(Value, Base);
    public short AsI16 => Convert.ToInt16(Value, Base);
    public byte AsU8 => Convert.ToByte(Value, Base);
    public sbyte AsI8 => Convert.ToSByte(Value, Base);

    public float AsF32 => Convert.ToSingle(AsI32);
    public double AsF64 => Convert.ToDouble(AsI64);

    public override string ToString()
    {
        return Value;
    }
}

public record StringLiteralToken(SourceSpan Span, string Value) : Token(Span)
{
    public override string ToString()
    {
        return $"\"{Value}\"";
    }
}

public record BoolLiteralToken(SourceSpan Span, bool Value) : Token(Span)
{
    public override string ToString()
    {
        return Value ? "true" : "false";
    }
}

public record FloatLiteralToken(SourceSpan Span, string Value) : Token(Span)
{
    public float AsF32 => Convert.ToSingle(Value);
    public double AsF64 => Convert.ToDouble(Value);

    public override string ToString()
    {
        return Value;
    }
}

public enum Symbol
{
    // Default
    None,

    // Control
    If,
    Else,
    While,
    For,
    In,
    Break,
    Continue,
    Return,
    Let,
    Defer,

    // Declaration
    Func,
    Struct,
    Enum,
    Import,
    Module,

    // Modifier
    Extern,
    Packed,
    Export,

    Colon,
    DoubleColon,
    OpenParen,
    CloseParen,
    OpenBrace,
    CloseBrace,
    OpenBracket,
    CloseBracket,
    Comma,
    Period,
    Assign,
    Bang,
    Equal,
    NotEqual,
    LessThan,
    LessThanOrEqual,
    GreaterThan,
    GreaterThanOrEqual,
    Plus,
    Minus,
    Star,
    ForwardSlash,
    Caret,
    Ampersand,
    Semi,
    Percent,
    LeftShift,
    RightShift,
    Pipe,
    And,
    Or,
    At,
    QuestionMark,
}

public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
{
    public override string ToString()
    {
        return Symbol switch
        {
            Symbol.Func => "func",
            Symbol.If => "if",
            Symbol.Else => "else",
            Symbol.While => "while",
            Symbol.For => "for",
            Symbol.In => "in",
            Symbol.Break => "break",
            Symbol.Continue => "continue",
            Symbol.Return => "return",
            Symbol.Struct => "struct",
            Symbol.Let => "let",
            Symbol.Extern => "extern",
            Symbol.Module => "module",
            Symbol.Export => "export",
            Symbol.Import => "import",
            Symbol.Defer => "defer",
            Symbol.Enum => "enum",
            Symbol.Equal => "==",
            Symbol.NotEqual => "!=",
            Symbol.LessThanOrEqual => "<=",
            Symbol.GreaterThanOrEqual => ">=",
            Symbol.LeftShift => "<<",
            Symbol.RightShift => ">>",
            Symbol.And => "&&",
            Symbol.Or => "||",
            Symbol.DoubleColon => "::",
            Symbol.Colon => ":",
            Symbol.OpenParen => "(",
            Symbol.CloseParen => ")",
            Symbol.OpenBrace => "{",
            Symbol.CloseBrace => "}",
            Symbol.OpenBracket => "[",
            Symbol.CloseBracket => "]",
            Symbol.Comma => ",",
            Symbol.Period => ".",
            Symbol.Assign => "=",
            Symbol.LessThan => "<",
            Symbol.GreaterThan => ">",
            Symbol.Plus => "+",
            Symbol.Minus => "-",
            Symbol.Star => "*",
            Symbol.ForwardSlash => "/",
            Symbol.Bang => "!",
            Symbol.Caret => "^",
            Symbol.Ampersand => "&",
            Symbol.Semi => ";",
            Symbol.Percent => "%",
            Symbol.Pipe => "|",
            Symbol.At => "@",
            Symbol.QuestionMark => "?",
            _ => "none",
        };
    }
}