defmodule Symbiont.DispatcherTest do
  use ExUnit.Case, async: false

  @moduletag :capture_log

  setup do
    tmp_dir = Path.join(System.tmp_dir!(), "symbiont_dispatch_test_#{:rand.uniform(999_999)}")
    File.mkdir_p!(tmp_dir)

    # Start a fresh ledger for logging
    if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger)
    {:ok, _pid} = Symbiont.Ledger.start_link(data_dir: tmp_dir)

    on_exit(fn ->
      if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger)
      File.rm_rf!(tmp_dir)
    end)

    %{tmp_dir: tmp_dir}
  end

  test "invoke with echo CLI returns result and logs to ledger" do
    # In test config, claude_cli is "echo" — so System.cmd("echo", [...], input: prompt)
    # echo doesn't actually read stdin, it echoes its args
    result = Symbiont.Dispatcher.invoke(:haiku, "Hello world")

    case result do
      {:ok, entry} ->
        assert entry.model == "haiku"
        assert entry.success == true
        assert is_float(entry.elapsed_seconds)
        assert entry.estimated_cost_usd >= 0

        # Ledger should have recorded it
        Process.sleep(50)
        entries = Symbiont.Ledger.recent()
        assert length(entries) >= 1

      {:error, _reason} ->
        # echo might not be on path in all environments
        :ok
    end
  end

  test "invoke records prompt preview in ledger entry" do
    long_prompt = String.duplicate("x", 200)
    result = Symbiont.Dispatcher.invoke(:sonnet, long_prompt)

    case result do
      {:ok, entry} ->
        # Prompt preview should be truncated to 100 chars
        assert String.length(entry.prompt_preview) <= 100

      {:error, _} ->
        :ok
    end
  end

  test "cost estimation is reasonable" do
    # Test that the internal cost math works
    # Haiku: 0.00000025/input + 0.00000125/output
    # 1000 input + 500 output = 0.00025 + 0.000625 = 0.000875
    result = Symbiont.Dispatcher.invoke(:haiku, "test")

    case result do
      {:ok, entry} ->
        assert entry.estimated_cost_usd >= 0
        assert entry.estimated_cost_usd < 1.0

      {:error, _} ->
        :ok
    end
  end
end
