defmodule Tarakan.ScansFixtures do
  @moduledoc """
  Test helpers for creating entities via the `Tarakan.Scans` context.
  """

  import Tarakan.AccountsFixtures

  alias Tarakan.Repositories
  alias Tarakan.Scans
  alias Tarakan.Accounts.Account

  @doc """
  Registers the one repository the GitHub stub can verify.
  """
  def github_repository_fixture(account \\ nil) do
    account = account || github_account_fixture()
    {:ok, repository} = Repositories.register_github_repository("openai/codex", account)
    repository
  end

  @doc "Registers the GitHub fixture and makes it visible for public-record tests."
  def listed_github_repository_fixture(account \\ nil) do
    account
    |> github_repository_fixture()
    |> listed_repository_fixture()
  end

  @doc """
  Inserts a listed Tarakan-hosted repository record.

  Goes through the schema rather than `Tarakan.HostedRepositories.create/2` so
  no bare repository is written to disk.
  """
  def listed_hosted_repository_fixture(account \\ nil) do
    account = account || github_account_fixture()

    %Tarakan.Repositories.Repository{}
    |> Tarakan.Repositories.Repository.hosted_changeset(
      %{"name" => "hosted-#{System.unique_integer([:positive])}", "description" => "Hosted."},
      account.handle
    )
    |> Ecto.Changeset.put_change(:submitted_by_id, account.id)
    |> Tarakan.Repo.insert!()
    |> listed_repository_fixture()
  end

  def listed_repository_fixture(repository) do
    repository
    |> Tarakan.Repositories.Repository.listing_changeset(%{listing_status: "listed"})
    |> Tarakan.Repo.update!()
  end

  def valid_scan_attributes(overrides \\ %{}) do
    Enum.into(overrides, %{
      "commit_sha" => random_commit_sha(),
      "model" => "claude-sonnet-5",
      "prompt_version" => "tarakan-baseline/v1",
      "run_id" => "fixture-#{System.unique_integer([:positive, :monotonic])}",
      "findings_json" => nil
    })
  end

  def scan_fixture(repository, account, overrides \\ %{}) do
    {:ok, scan} = Scans.submit_scan(repository, account, valid_scan_attributes(overrides))
    scan
  end

  def confirmation_fixture(scan, account, verdict \\ "confirmed") do
    account = reviewer_account(account)

    {:ok, scan} =
      Scans.record_confirmation(scan, account, %{
        "verdict" => verdict,
        "notes" =>
          "Independently traced and reproduced the reported behavior in a local checkout."
      })

    scan
  end

  def reviewer_account_fixture do
    account_fixture() |> reviewer_account()
  end

  def moderator_account_fixture do
    account_fixture() |> moderator_account()
  end

  def moderator_account(account) do
    account
    |> Account.authorization_changeset(%{
      state: "active",
      platform_role: "moderator",
      trust_tier: "reviewer"
    })
    |> Tarakan.Repo.update!()
  end

  def reviewer_account(%Account{platform_role: "moderator", trust_tier: "reviewer"} = account),
    do: account

  def reviewer_account(account) do
    account
    |> Account.authorization_changeset(%{
      state: "active",
      platform_role: "moderator",
      trust_tier: "reviewer"
    })
    |> Tarakan.Repo.update!()
  end

  def findings_json_fixture(count \\ 1) do
    findings =
      for index <- 1..count do
        %{
          "file" => "lib/example/module_#{index}.ex",
          "line_start" => index * 10,
          "line_end" => index * 10 + 5,
          "severity" => "high",
          "title" => "Unsanitized input reaches interpolated query (#{index})",
          "description" => "String-built SQL executed with request parameters."
        }
      end

    Jason.encode!(%{"tarakan_scan_format" => 1, "findings" => findings})
  end

  def random_commit_sha do
    16 |> :crypto.strong_rand_bytes() |> Base.encode16(case: :lower) |> Kernel.<>("00000000")
  end
end
