/**
 * Adapter Factory Tests
 * Verifies model options are correctly passed to adapters
 */

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { createLLMAdapter } from '../server/adapter-factory'
import type { ModelConfig } from '../../model-info'

// Mock OpenAI SDK
vi.mock('openai', () => {
  return {
    default: vi.fn().mockImplementation(() => ({
      chat: {
        completions: {
          create: vi.fn()
        }
      }
    }))
  }
})

describe('createLLMAdapter - Vendor Options', () => {
  beforeEach(() => {
    vi.clearAllMocks()
  })

  describe('Model Options - Flat Structure', () => {
    it('accepts flat model options (no vendor namespace)', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          reasoning_effort: 'low',
          verbosity: 'low'
        }
      }

      const adapter = createLLMAdapter(config)

      expect(adapter).toBeDefined()
    })

    it('passes all options directly to adapter (flat structure)', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          reasoning_effort: 'high',
          verbosity: 'medium'
        }
      }

      const adapter = createLLMAdapter(config)

      expect(adapter).toBeDefined()
    })
  })

  describe('Backward Compatibility', () => {
    it('creates adapter with legacy config (no model options)', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        temperature: 0.7,
        maxOutputTokens: 1000
      }

      const adapter = createLLMAdapter(config)

      expect(adapter).toBeDefined()
    })

    it('creates mock adapter without model options', () => {
      const config: ModelConfig = {
        provider: 'mock',
        model: 'mock',
        apiKey: 'test-key'
      }

      const adapter = createLLMAdapter(config)

      expect(adapter).toBeDefined()
    })

    it('creates mock adapter with model options (should be ignored)', () => {
      const config: ModelConfig = {
        provider: 'mock',
        model: 'mock',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'low'
          }
        }
      }

      const adapter = createLLMAdapter(config)

      // Mock adapter doesn't use model options, but config should still be valid
      expect(adapter).toBeDefined()
    })
  })

  describe('All Reasoning Effort Levels', () => {
    it('creates adapter with low reasoning effort', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'low'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates adapter with medium reasoning effort', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'medium'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates adapter with high reasoning effort', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'high'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })
  })

  describe('All Text Verbosity Levels', () => {
    it('creates adapter with low text verbosity', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            verbosity: 'low'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates adapter with medium text verbosity', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            verbosity: 'medium'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates adapter with high text verbosity', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            verbosity: 'high'
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })
  })

  describe('Integration with Observability', () => {
    it('creates adapter with model options and AI usage collector', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'low'
          }
        }
      }

      const mockCollector = {
        recordCall: vi.fn(),
        getTotalCalls: vi.fn(),
        getTotalTokens: vi.fn()
      } as unknown

      const adapter = createLLMAdapter(config, mockCollector as never)

      expect(adapter).toBeDefined()
    })

    it('creates adapter with model options and call context', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'medium',
            verbosity: 'low'
          }
        }
      }

      const mockCollector = {
        recordCall: vi.fn(),
        getTotalCalls: vi.fn(),
        getTotalTokens: vi.fn()
      } as unknown

      const adapter = createLLMAdapter(config, mockCollector as never, 'agent-iteration', {
        agentId: 'test-agent',
        sessionId: 'test-session',
        organizationId: 'test-org'
      })

      expect(adapter).toBeDefined()
    })
  })

  describe('OpenRouter Provider', () => {
    it('creates OpenRouter adapter for openrouter/ prefixed models', () => {
      const config: ModelConfig = {
        provider: 'openrouter',
        model: 'openrouter/anthropic/claude-sonnet-4.5',
        apiKey: 'sk-or-v1-test-key'
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates OpenRouter adapter with model options', () => {
      const config: ModelConfig = {
        provider: 'openrouter',
        model: 'openrouter/anthropic/claude-sonnet-4.5',
        apiKey: 'sk-or-v1-test-key',
        modelOptions: {
          transforms: ['middle-out'],
          route: 'fallback'
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('creates OpenRouter adapter for supported models', () => {
      const models: ModelConfig[] = [
        {
          provider: 'openrouter',
          model: 'openrouter/anthropic/claude-sonnet-4.5',
          apiKey: 'sk-or-v1-test-key'
        },
        {
          provider: 'openrouter',
          model: 'openrouter/deepseek/deepseek-v3.2',
          apiKey: 'sk-or-v1-test-key'
        },
        {
          provider: 'openrouter',
          model: 'openrouter/x-ai/grok-4.1-fast',
          apiKey: 'sk-or-v1-test-key'
        }
      ]

      for (const config of models) {
        const adapter = createLLMAdapter(config)
        expect(adapter).toBeDefined()
      }
    })
  })

  describe('Edge Cases', () => {
    it('handles undefined model options', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: undefined
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('handles empty openai model options object', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          openai: {}
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('handles partial model options (only reasoning)', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            reasoning_effort: 'low'
            // text option omitted
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })

    it('handles partial model options (only text)', () => {
      const config: ModelConfig = {
        provider: 'openai',
        model: 'gpt-5-mini',
        apiKey: 'test-key',
        modelOptions: {
          openai: {
            verbosity: 'high'
            // reasoning option omitted
          }
        }
      }

      const adapter = createLLMAdapter(config)
      expect(adapter).toBeDefined()
    })
  })
})
