# frozen_string_literal: true
# Offline test adapter only. No sockets, inference, or benchmark measurements.
require 'net/http'
require 'json'
MAIN = Thread.current
CALLS = []
LOCK = Mutex.new
PROMPT = 'Explain in plain words how a key-value cache speeds up text generation in a transformer. ' * 4
module Process
  def self.clock_gettime(*)
    Thread.current[:tick] ||= 0
    i = Thread.current[:tick]
    Thread.current[:tick] += 1
    Thread.current == MAIN ? [0.0, 10.0, 20.0, 60.0].fetch(i) : [0.0, 10.0].fetch(i)
  end
end
class FixtureHTTP
  def initialize(port)
    @port = port
  end

  def post(path, body, headers)
    raise 'content type' unless headers == {'Content-Type' => 'application/json'}
    j = JSON.parse(body)
    prompt = j.delete('prompt')
    if @port == 8195
      raise 'path' unless path == '/completion'
      expected = {'n_predict'=>200, 'temperature'=>0, 'seed'=>1, 'ignore_eos'=>true, 'cache_prompt'=>false}
      response = {'tokens_predicted'=>200, 'timings'=>{'predicted_per_second'=>20.0}}
    else
      raise 'path' unless path == '/api/generate'
      expected = {'model'=>'qwen3:4b', 'stream'=>false, 'think'=>false,
                  'options'=>{'num_predict'=>200, 'temperature'=>0, 'seed'=>1}}
      response = {'eval_count'=>200, 'eval_duration'=>10_000_000_000,
                  'prompt_eval_count'=>70, 'prompt_eval_duration'=>1_000_000_000}
    end
    raise 'request configuration mismatch' unless j == expected
    LOCK.synchronize { CALLS << [@port, prompt] }
    Struct.new(:body).new(JSON.generate(response))
  end
end
module Net
  class HTTP
    def self.start(host, port, **options)
      raise 'endpoint' unless host == '127.0.0.1' && [8195,11434].include?(port)
      raise 'timeout' unless options == {read_timeout: 600}
      yield FixtureHTTP.new(port)
    end
  end
end
at_exit do
  unless $!
    port = CALLS.first&.first
    expected = ['hi'] + (port == 8195 ? (0...4).map { |i| "#{i} #{PROMPT}" } : [PROMPT] * 4)
    raise 'warmup or exact prompt mismatch' unless CALLS.map(&:last).sort == expected.sort
  end
end
