import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import {
  resolveModelString,
  getEffectiveModel,
  CLAUDE_MODEL_MAP,
  DEFAULT_MODELS,
} from '@automaker/model-resolver';

describe('model-resolver.ts', () => {
  let consoleSpy: any;

  beforeEach(() => {
    consoleSpy = {
      log: vi.spyOn(console, 'log').mockImplementation(() => {}),
      warn: vi.spyOn(console, 'warn').mockImplementation(() => {}),
    };
  });

  afterEach(() => {
    consoleSpy.log.mockRestore();
    consoleSpy.warn.mockRestore();
  });

  describe('resolveModelString', () => {
    it("should resolve 'haiku' alias to full model string", () => {
      const result = resolveModelString('haiku');
      expect(result).toBe(CLAUDE_MODEL_MAP.haiku);
    });

    it("should resolve 'sonnet' alias to full model string", () => {
      const result = resolveModelString('sonnet');
      expect(result).toBe(CLAUDE_MODEL_MAP.sonnet);
    });

    it("should resolve 'opus' alias to full model string", () => {
      const result = resolveModelString('opus');
      expect(result).toBe('claude-opus-4-5-20251101');
      expect(consoleSpy.log).toHaveBeenCalledWith(
        expect.stringContaining('Resolved model alias: "opus"')
      );
    });

    it('should treat unknown models as falling back to default', () => {
      const models = ['o1', 'o1-mini', 'o3', 'gpt-5.2', 'unknown-model'];
      models.forEach((model) => {
        const result = resolveModelString(model);
        // Should fall back to default since these aren't supported
        expect(result).toBe(DEFAULT_MODELS.claude);
      });
    });

    it('should pass through full Claude model strings', () => {
      const models = [CLAUDE_MODEL_MAP.opus, CLAUDE_MODEL_MAP.sonnet, CLAUDE_MODEL_MAP.haiku];
      models.forEach((model) => {
        const result = resolveModelString(model);
        expect(result).toBe(model);
      });
      expect(consoleSpy.log).toHaveBeenCalledWith(
        expect.stringContaining('Using full Claude model string')
      );
    });

    it('should return default model when modelKey is undefined', () => {
      const result = resolveModelString(undefined);
      expect(result).toBe(DEFAULT_MODELS.claude);
    });

    it('should return custom default model when provided', () => {
      const customDefault = 'custom-model';
      const result = resolveModelString(undefined, customDefault);
      expect(result).toBe(customDefault);
    });

    it('should return default for unknown model key', () => {
      const result = resolveModelString('unknown-model');
      expect(result).toBe(DEFAULT_MODELS.claude);
      expect(consoleSpy.warn).toHaveBeenCalledWith(
        expect.stringContaining('Unknown model key "unknown-model"')
      );
    });

    it('should handle empty string', () => {
      const result = resolveModelString('');
      expect(result).toBe(DEFAULT_MODELS.claude);
    });
  });

  describe('getEffectiveModel', () => {
    it('should prioritize explicit model over session and default', () => {
      const result = getEffectiveModel('opus', 'haiku', 'gpt-5.2');
      expect(result).toBe('claude-opus-4-5-20251101');
    });

    it('should use session model when explicit is not provided', () => {
      const result = getEffectiveModel(undefined, 'sonnet', 'gpt-5.2');
      expect(result).toBe(CLAUDE_MODEL_MAP.sonnet);
    });

    it('should use default when neither explicit nor session is provided', () => {
      const customDefault = CLAUDE_MODEL_MAP.haiku;
      const result = getEffectiveModel(undefined, undefined, customDefault);
      expect(result).toBe(customDefault);
    });

    it('should use Claude default when no arguments provided', () => {
      const result = getEffectiveModel();
      expect(result).toBe(DEFAULT_MODELS.claude);
    });

    it('should handle explicit empty strings as undefined', () => {
      const result = getEffectiveModel('', 'haiku');
      expect(result).toBe(CLAUDE_MODEL_MAP.haiku);
    });
  });

  describe('CLAUDE_MODEL_MAP', () => {
    it('should have haiku, sonnet, opus mappings', () => {
      expect(CLAUDE_MODEL_MAP).toHaveProperty('haiku');
      expect(CLAUDE_MODEL_MAP).toHaveProperty('sonnet');
      expect(CLAUDE_MODEL_MAP).toHaveProperty('opus');
    });

    it('should have valid Claude model strings', () => {
      expect(CLAUDE_MODEL_MAP.haiku).toContain('haiku');
      expect(CLAUDE_MODEL_MAP.sonnet).toContain('sonnet');
      expect(CLAUDE_MODEL_MAP.opus).toContain('opus');
    });
  });

  describe('DEFAULT_MODELS', () => {
    it('should have claude default', () => {
      expect(DEFAULT_MODELS).toHaveProperty('claude');
    });

    it('should have valid default model', () => {
      expect(DEFAULT_MODELS.claude).toContain('claude');
    });
  });
});
