defmodule Symbiont.QueueTest do
  use ExUnit.Case, async: false
  import Symbiont.TestHelpers

  @moduletag :capture_log

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

    safe_stop(Symbiont.Queue)
    {:ok, _pid} = Symbiont.Queue.start_link(data_dir: tmp_dir)

    on_exit(fn ->
      safe_stop(Symbiont.Queue)
      File.rm_rf!(tmp_dir)
    end)

    %{tmp_dir: tmp_dir}
  end

  test "starts with empty queue" do
    assert Symbiont.Queue.size() == 0
    assert Symbiont.Queue.list() == []
  end

  test "enqueue adds tasks and returns IDs" do
    {:ok, id1} = Symbiont.Queue.enqueue("Task one")
    {:ok, id2} = Symbiont.Queue.enqueue("Task two", "high")

    assert is_binary(id1)
    assert is_binary(id2)
    assert id1 != id2
    assert Symbiont.Queue.size() == 2
  end

  test "take returns pending tasks and marks them as processing" do
    {:ok, _} = Symbiont.Queue.enqueue("Task A")
    {:ok, _} = Symbiont.Queue.enqueue("Task B")
    {:ok, _} = Symbiont.Queue.enqueue("Task C")

    taken = Symbiont.Queue.take(2)
    assert length(taken) == 2
    assert Enum.all?(taken, &(&1["status"] == "processing"))

    # Only 1 pending remains
    assert Symbiont.Queue.size() == 1
  end

  test "complete marks a task as done" do
    {:ok, id} = Symbiont.Queue.enqueue("Complete me")
    [task] = Symbiont.Queue.take(1)
    assert task["id"] == id

    Symbiont.Queue.complete(id, "All done!")
    Process.sleep(50)

    tasks = Symbiont.Queue.list()
    done = Enum.find(tasks, &(&1["id"] == id))
    assert done["status"] == "done"
    assert done["result"] == "All done!"
  end

  test "fail marks a task as failed" do
    {:ok, id} = Symbiont.Queue.enqueue("Fail me")
    _taken = Symbiont.Queue.take(1)

    Symbiont.Queue.fail(id, "something broke")
    Process.sleep(50)

    tasks = Symbiont.Queue.list()
    failed = Enum.find(tasks, &(&1["id"] == id))
    assert failed["status"] == "failed"
    assert failed["result"] == "something broke"
  end

  test "list filters by status" do
    {:ok, _} = Symbiont.Queue.enqueue("Pending 1")
    {:ok, _} = Symbiont.Queue.enqueue("To complete")

    # Take one task (first pending)
    [taken] = Symbiont.Queue.take(1)
    # Complete the taken task
    Symbiont.Queue.complete(taken["id"], "done")
    Process.sleep(50)

    pending = Symbiont.Queue.list("pending")
    assert length(pending) == 1

    done = Symbiont.Queue.list("done")
    assert length(done) == 1
  end

  test "queue persists to JSONL file", %{tmp_dir: tmp_dir} do
    {:ok, _} = Symbiont.Queue.enqueue("Persistent task")

    path = Path.join(tmp_dir, "queue.jsonl")
    content = File.read!(path)
    assert String.contains?(content, "Persistent task")
    assert String.contains?(content, "pending")
  end

  test "queue loads tasks from file on restart", %{tmp_dir: tmp_dir} do
    {:ok, _} = Symbiont.Queue.enqueue("Survivor task")
    assert Symbiont.Queue.size() == 1

    # Stop and restart
    GenServer.stop(Symbiont.Queue)
    {:ok, _} = Symbiont.Queue.start_link(data_dir: tmp_dir)

    assert Symbiont.Queue.size() == 1
    [task] = Symbiont.Queue.list("pending")
    assert task["task"] == "Survivor task"
  end

end
