using Xunit;
using SynorCompute;

namespace SynorCompute.Tests;

public class TypesTests
{
    [Fact]
    public void ProcessorType_HasAllValues()
    {
        Assert.Equal("cpu", ProcessorType.Cpu.ToValue());
        Assert.Equal("gpu", ProcessorType.Gpu.ToValue());
        Assert.Equal("tpu", ProcessorType.Tpu.ToValue());
        Assert.Equal("npu", ProcessorType.Npu.ToValue());
        Assert.Equal("lpu", ProcessorType.Lpu.ToValue());
        Assert.Equal("auto", ProcessorType.Auto.ToValue());
    }

    [Fact]
    public void ProcessorType_ParsesFromString()
    {
        Assert.Equal(ProcessorType.Gpu, ProcessorTypeExtensions.FromString("gpu"));
        Assert.Equal(ProcessorType.Tpu, ProcessorTypeExtensions.FromString("tpu"));
        Assert.Equal(ProcessorType.Auto, ProcessorTypeExtensions.FromString("invalid"));
    }

    [Fact]
    public void Precision_HasAllValues()
    {
        Assert.Equal("fp64", Precision.FP64.ToValue());
        Assert.Equal("fp32", Precision.FP32.ToValue());
        Assert.Equal("fp16", Precision.FP16.ToValue());
        Assert.Equal("bf16", Precision.BF16.ToValue());
        Assert.Equal("int8", Precision.INT8.ToValue());
        Assert.Equal("int4", Precision.INT4.ToValue());
    }

    [Fact]
    public void Priority_HasAllValues()
    {
        Assert.Equal("critical", Priority.Critical.ToValue());
        Assert.Equal("high", Priority.High.ToValue());
        Assert.Equal("normal", Priority.Normal.ToValue());
        Assert.Equal("low", Priority.Low.ToValue());
        Assert.Equal("background", Priority.Background.ToValue());
    }

    [Fact]
    public void JobStatus_HasAllValues()
    {
        Assert.Equal("pending", JobStatus.Pending.ToValue());
        Assert.Equal("queued", JobStatus.Queued.ToValue());
        Assert.Equal("running", JobStatus.Running.ToValue());
        Assert.Equal("completed", JobStatus.Completed.ToValue());
        Assert.Equal("failed", JobStatus.Failed.ToValue());
        Assert.Equal("cancelled", JobStatus.Cancelled.ToValue());
    }

    [Fact]
    public void JobStatus_IdentifiesTerminalStates()
    {
        Assert.True(JobStatus.Completed.IsTerminal());
        Assert.True(JobStatus.Failed.IsTerminal());
        Assert.True(JobStatus.Cancelled.IsTerminal());
        Assert.False(JobStatus.Pending.IsTerminal());
        Assert.False(JobStatus.Running.IsTerminal());
    }

    [Fact]
    public void SynorConfig_CreatesWithDefaults()
    {
        var config = new SynorConfig("test-key");

        Assert.Equal("test-key", config.ApiKey);
        Assert.Equal("https://api.synor.io/compute/v1", config.BaseUrl);
        Assert.Equal(TimeSpan.FromSeconds(30), config.Timeout);
        Assert.Equal(ProcessorType.Auto, config.DefaultProcessor);
        Assert.Equal(Precision.FP32, config.DefaultPrecision);
    }

    [Fact]
    public void SynorConfig_CreatesWithCustomValues()
    {
        var config = new SynorConfig("test-key")
        {
            BaseUrl = "https://custom.api.com",
            Timeout = TimeSpan.FromSeconds(60),
            DefaultProcessor = ProcessorType.Gpu,
            DefaultPrecision = Precision.FP16
        };

        Assert.Equal("https://custom.api.com", config.BaseUrl);
        Assert.Equal(TimeSpan.FromSeconds(60), config.Timeout);
        Assert.Equal(ProcessorType.Gpu, config.DefaultProcessor);
    }

    [Fact]
    public void MatMulOptions_HasCorrectDefaults()
    {
        var options = new MatMulOptions();

        Assert.Equal(Precision.FP32, options.Precision);
        Assert.Equal(ProcessorType.Auto, options.Processor);
        Assert.Equal(Priority.Normal, options.Priority);
    }

    [Fact]
    public void Conv2dOptions_HasCorrectDefaults()
    {
        var options = new Conv2dOptions();

        Assert.Equal((1, 1), options.Stride);
        Assert.Equal((0, 0), options.Padding);
    }

    [Fact]
    public void AttentionOptions_HasCorrectDefaults()
    {
        var options = new AttentionOptions();

        Assert.Equal(8, options.NumHeads);
        Assert.True(options.Flash);
        Assert.Equal(Precision.FP16, options.Precision);
    }

    [Fact]
    public void InferenceOptions_HasCorrectDefaults()
    {
        var options = new InferenceOptions();

        Assert.Equal(256, options.MaxTokens);
        Assert.Equal(0.7, options.Temperature, 3);
        Assert.Equal(0.9, options.TopP, 3);
        Assert.Equal(50, options.TopK);
    }

    [Fact]
    public void JobResult_IdentifiesSuccess()
    {
        var result = new JobResult<string>
        {
            JobId = "job-123",
            Status = JobStatus.Completed,
            Result = "output"
        };

        Assert.True(result.IsSuccess);
        Assert.False(result.IsFailed);
    }

    [Fact]
    public void JobResult_IdentifiesFailure()
    {
        var result = new JobResult<string>
        {
            JobId = "job-456",
            Status = JobStatus.Failed,
            Error = "Error message"
        };

        Assert.False(result.IsSuccess);
        Assert.True(result.IsFailed);
    }

    [Fact]
    public void ModelInfo_FormatsParametersCorrectly()
    {
        var model = new ModelInfo
        {
            Id = "test",
            Name = "Test Model",
            Category = "llm",
            Parameters = 70_000_000_000
        };

        Assert.Equal("70B", model.FormattedParameters);
    }

    [Fact]
    public void ModelInfo_FormatsParametersInMillions()
    {
        var model = new ModelInfo
        {
            Id = "test",
            Name = "Test Model",
            Category = "embedding",
            Parameters = 350_000_000
        };

        Assert.Equal("350M", model.FormattedParameters);
    }
}
