import { describe, it, expect } from 'vitest';
import {
  LlamaProviderSchema,
  LlamaProvidersFileSchema,
  parseModelRef,
  formatModelRef,
} from '../llama-providers.js';

const VALID_PROVIDER = {
  id: 'sam-desktop',
  label: 'Sam-desktop',
  baseUrl: 'http://100.101.41.16:8401',
  kind: 'llama-swap',
};

const VALID_MINIMAL_PROVIDER = {
  id: 'embedding',
  label: 'embedding',
  baseUrl: 'http://100.90.172.55:8411',
  kind: 'llama-swap',
};

const VALID_FILE = {
  defaultProvider: 'sam-desktop',
  providers: [VALID_PROVIDER, VALID_MINIMAL_PROVIDER],
};

describe('LlamaProviderSchema', () => {
  it('accepts a well-formed provider', () => {
    const result = LlamaProviderSchema.safeParse(VALID_PROVIDER);
    expect(result.success).toBe(true);
  });

  it('defaults kind to llama-swap', () => {
    const result = LlamaProviderSchema.safeParse({
      id: 'test',
      label: 'test',
      baseUrl: 'http://localhost:8080',
    });
    expect(result.success).toBe(true);
    if (result.success) {
      expect(result.data.kind).toBe('llama-swap');
    }
  });

  it('rejects missing id', () => {
    const result = LlamaProviderSchema.safeParse({
      label: 'test',
      baseUrl: 'http://localhost:8080',
    });
    expect(result.success).toBe(false);
  });

  it('rejects empty id', () => {
    const result = LlamaProviderSchema.safeParse({
      id: '',
      label: 'test',
      baseUrl: 'http://localhost:8080',
    });
    expect(result.success).toBe(false);
  });

  it('rejects invalid baseUrl', () => {
    const result = LlamaProviderSchema.safeParse({
      id: 'test',
      label: 'test',
      baseUrl: 'not-a-url',
    });
    expect(result.success).toBe(false);
  });
});

describe('LlamaProvidersFileSchema', () => {
  it('accepts a well-formed file', () => {
    const result = LlamaProvidersFileSchema.safeParse(VALID_FILE);
    expect(result.success).toBe(true);
  });

  it('rejects missing defaultProvider', () => {
    const result = LlamaProvidersFileSchema.safeParse({
      providers: [VALID_PROVIDER],
    });
    expect(result.success).toBe(false);
  });

  it('rejects empty providers array', () => {
    const result = LlamaProvidersFileSchema.safeParse({
      defaultProvider: 'sam-desktop',
      providers: [],
    });
    expect(result.success).toBe(false);
  });

  it('rejects when defaultProvider references nonexistent provider id', () => {
    // Schema doesn't enforce cross-reference, but the file shape is valid.
    const result = LlamaProvidersFileSchema.safeParse({
      defaultProvider: 'nonexistent',
      providers: [VALID_PROVIDER],
    });
    expect(result.success).toBe(true);
  });
});

describe('parseModelRef', () => {
  const defaultProvider = 'sam-desktop';

  it('parses composite provider/model', () => {
    const result = parseModelRef('sam-desktop/qwen3.6-35b-a3b', defaultProvider);
    expect(result).toEqual({
      providerId: 'sam-desktop',
      wireModelId: 'qwen3.6-35b-a3b',
      isLegacyBareId: false,
    });
  });

  it('parses composite with model containing slashes', () => {
    const result = parseModelRef('sam-desktop/deepseek/v4-pro', defaultProvider);
    expect(result).toEqual({
      providerId: 'sam-desktop',
      wireModelId: 'deepseek/v4-pro',
      isLegacyBareId: false,
    });
  });

  it('resolves bare id to default provider', () => {
    const result = parseModelRef('qwen3.6-35b-a3b', defaultProvider);
    expect(result).toEqual({
      providerId: 'sam-desktop',
      wireModelId: 'qwen3.6-35b-a3b',
      isLegacyBareId: true,
    });
  });

  it('resolves empty string to default provider', () => {
    const result = parseModelRef('', defaultProvider);
    expect(result).toEqual({
      providerId: 'sam-desktop',
      wireModelId: '',
      isLegacyBareId: true,
    });
  });

  it('parses embedding provider/model', () => {
    const result = parseModelRef('embedding/gemma-4-12b', defaultProvider);
    expect(result).toEqual({
      providerId: 'embedding',
      wireModelId: 'gemma-4-12b',
      isLegacyBareId: false,
    });
  });

  it('does not strip provider prefix when first char is slash', () => {
    // "/model" has slashIdx=0, so treated as bare id.
    const result = parseModelRef('/model', defaultProvider);
    expect(result).toEqual({
      providerId: 'sam-desktop',
      wireModelId: '/model',
      isLegacyBareId: true,
    });
  });
});

describe('formatModelRef', () => {
  it('formats provider/model', () => {
    expect(formatModelRef('sam-desktop', 'qwen3.6-35b-a3b')).toBe('sam-desktop/qwen3.6-35b-a3b');
  });

  it('formats provider with model containing slashes', () => {
    expect(formatModelRef('sam-desktop', 'deepseek/v4-pro')).toBe('sam-desktop/deepseek/v4-pro');
  });

  it('round-trips through parseModelRef', () => {
    const formatted = formatModelRef('embedding', 'gemma-4-12b');
    const parsed = parseModelRef(formatted, 'sam-desktop');
    expect(parsed.providerId).toBe('embedding');
    expect(parsed.wireModelId).toBe('gemma-4-12b');
    expect(parsed.isLegacyBareId).toBe(false);
  });
});
