defmodule TarakanWeb.API.FindingControllerTest do
  use TarakanWeb.ConnCase

  setup do
    submitter = github_account_fixture()
    repository = listed_github_repository_fixture(submitter)
    %{repository: repository, submitter: submitter}
  end

  test "returns a serialized public finding", %{
    conn: conn,
    repository: repository,
    submitter: submitter
  } do
    scan =
      repository
      |> scan_fixture(submitter, %{"findings_json" => findings_json_with_disclosure_fixture()})
      |> publish_scan("public")

    [finding] = scan.findings

    conn = get(conn, ~p"/api/findings/#{finding.public_id}")

    assert %{"finding" => data} = json_response(conn, 200)
    assert data["public_id"] == finding.public_id
    assert data["title"] == finding.title
    assert data["severity"] == "high"
    assert data["status"] == "verified"
    assert data["description"] =~ "String-built SQL"
    assert data["reproduction_steps"] =~ "Run the payload"
    assert data["affected_versions"] == ">= 1.0, < 2.0"
    assert data["cwe_id"] == "CWE-89"
    assert data["cve_id"] == "CVE-2026-12345"
    assert data["file_path"] == "lib/example/module_1.ex"
    assert data["line_start"] == 10
    assert data["line_end"] == 15
    assert data["first_seen_commit_sha"] == scan.commit_sha
    assert data["last_seen_commit_sha"] == scan.commit_sha
    assert data["verified_at"]
    assert is_map(data["counters"])
    assert data["repository"] == %{"host" => "github.com", "owner" => "openai", "name" => "codex"}
    assert data["record_url"] == TarakanWeb.Endpoint.url() <> "/findings/#{finding.public_id}"
    assert data["inserted_at"]
  end

  test "404s for a restricted finding", %{
    conn: conn,
    repository: repository,
    submitter: submitter
  } do
    scan = scan_fixture(repository, submitter, %{"findings_json" => findings_json_fixture(1)})

    {:ok, _restricted} =
      Tarakan.Scans.update_visibility(
        Tarakan.Accounts.Scope.for_account(moderator_account_fixture()),
        scan,
        "restricted",
        %{
          "moderation_reason" => "takedown_review",
          "moderation_notes" => "Restricted in this test to keep it off the public API."
        }
      )

    [finding] = scan.findings

    conn = get(conn, ~p"/api/findings/#{finding.public_id}")
    assert json_response(conn, 404)["error"] =~ "not found"
  end

  test "404s for a summary-only finding", %{
    conn: conn,
    repository: repository,
    submitter: submitter
  } do
    scan =
      repository
      |> scan_fixture(submitter, %{"findings_json" => findings_json_fixture(1)})
      |> publish_scan("public_summary")

    [finding] = scan.findings

    conn = get(conn, ~p"/api/findings/#{finding.public_id}")
    assert json_response(conn, 404)["error"] =~ "not found"
  end

  test "404s for an unknown public id", %{conn: conn} do
    conn = get(conn, ~p"/api/findings/#{Ecto.UUID.generate()}")
    assert json_response(conn, 404)["error"] =~ "not found"
  end

  defp findings_json_with_disclosure_fixture do
    Jason.encode!(%{
      "tarakan_scan_format" => 1,
      "findings" => [
        %{
          "file" => "lib/example/module_1.ex",
          "line_start" => 10,
          "line_end" => 15,
          "severity" => "high",
          "title" => "Unsanitized input reaches interpolated query (1)",
          "description" => "String-built SQL executed with request parameters.",
          "reproduction" => "1. Check out the pinned commit\n2. Run the payload",
          "affected_versions" => ">= 1.0, < 2.0",
          "cwe" => "CWE-89",
          "cve" => "CVE-2026-12345"
        }
      ]
    })
  end

  defp publish_scan(scan, visibility) do
    scan = confirmation_fixture(scan, reviewer_account_fixture())
    scan = confirmation_fixture(scan, reviewer_account_fixture())

    scope = Tarakan.Accounts.Scope.for_account(moderator_account_fixture())

    if visibility == "public" do
      scan.repository
      |> Tarakan.Repositories.Repository.participation_changeset(%{
        participation_mode: "maintainer_verified"
      })
      |> Tarakan.Repo.update!()
    end

    {:ok, scan} =
      Tarakan.Scans.accept_scan(scope, scan, %{
        "moderation_reason" => "evidence_reviewed",
        "moderation_notes" =>
          "Two independent reviewers supplied reproducible evidence for the pinned commit."
      })

    {:ok, scan} =
      Tarakan.Scans.update_visibility(scope, scan, visibility, %{
        "moderation_reason" => "disclosure_reviewed",
        "moderation_notes" =>
          "Disclosure was separately reviewed for scope, secrets, and personal data.",
        "sensitive_data_reviewed" => "true"
      })

    scan
  end
end
