defmodule TarakanWeb.BountyLiveTest do
  use TarakanWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  alias Tarakan.Accounts.Scope
  alias Tarakan.Market
  alias Tarakan.Market.Bounty
  alias Tarakan.Repo

  defp open_bounty do
    repository = listed_github_repository_fixture()
    sponsor = active_account_fixture() |> fund_credits(1_000)

    bounty = credits_bounty_fixture(Scope.for_account(sponsor), repository)
    {bounty, sponsor, repository}
  end

  describe "index" do
    test "renders open bounties for anonymous visitors", %{conn: conn} do
      {bounty, sponsor, _repository} = open_bounty()

      {:ok, view, html} = live(conn, ~p"/bounties")

      assert html =~ "Contracts"
      assert has_element?(view, "#bounties")
      assert has_element?(view, "#bounty-#{bounty.public_id}")
      assert html =~ bounty.title
      assert html =~ "500 credits"
      assert html =~ "@#{sponsor.handle}"
      assert has_element?(view, "#bounty-filters")
    end

    test "shows the empty state when nothing is open", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/bounties")

      assert has_element?(view, "#bounties-empty")
    end
  end

  describe "new" do
    test "redirects anonymous visitors to login", %{conn: conn} do
      assert {:error, {:redirect, %{to: "/accounts/log-in"}}} = live(conn, ~p"/bounties/new")
    end

    test "creates a credits bounty and lands on the poster", %{conn: conn} do
      repository = listed_github_repository_fixture()
      sponsor = active_account_fixture() |> fund_credits(1_000)
      conn = log_in_account(conn, sponsor)

      {:ok, view, _html} = live(conn, ~p"/bounties/new")

      assert has_element?(view, "#bounty-form")
      assert has_element?(view, "#bounty-credit-balance")

      # The target is picked from search, not typed.
      view
      |> form("#bounty-form", %{"bounty" => %{"repo_query" => repository.name}})
      |> render_change()

      assert view
             |> element("#bounty-repo-results button", "#{repository.owner}/#{repository.name}")
             |> render_click()

      assert has_element?(
               view,
               "#bounty-selected-repository",
               "#{repository.host}/#{repository.owner}/#{repository.name}"
             )

      {:ok, _show_view, html} =
        view
        |> form("#bounty-form", %{
          "bounty" => %{
            "target_type" => "repository",
            "title" => "Harden the webhook verifier",
            "description" => "Audit the signature verification path and ship a fix with tests.",
            "funding" => "credits",
            "amount" => "300"
          }
        })
        |> render_submit()
        |> follow_redirect(conn)

      assert html =~ "Harden the webhook verifier"
      assert html =~ "300 credits"

      bounty = Repo.one!(Bounty)
      assert bounty.status == "open"
      assert bounty.credit_amount == 300
      assert Tarakan.Credits.balance(sponsor) == 700
    end
  end

  describe "show" do
    test "anonymous visitors see the poster and a login prompt, not a claim button", %{
      conn: conn
    } do
      {bounty, _sponsor, _repository} = open_bounty()

      {:ok, view, html} = live(conn, ~p"/bounties/#{bounty.public_id}")

      assert html =~ bounty.title
      assert has_element?(view, "#bounty-status")
      refute has_element?(view, "#bounty-claim-button")
      assert has_element?(view, "#bounty-login-to-claim")
    end

    test "the sponsor sees cancel controls but no claim button", %{conn: conn} do
      {bounty, sponsor, _repository} = open_bounty()
      conn = log_in_account(conn, sponsor)

      {:ok, view, _html} = live(conn, ~p"/bounties/#{bounty.public_id}")

      refute has_element?(view, "#bounty-claim-button")
      assert has_element?(view, "#bounty-cancel-button")
    end

    test "an eligible hunter sees and uses the claim button", %{conn: conn} do
      {bounty, _sponsor, _repository} = open_bounty()
      hunter = active_account_fixture()
      conn = log_in_account(conn, hunter)

      {:ok, view, _html} = live(conn, ~p"/bounties/#{bounty.public_id}")

      assert has_element?(view, "#bounty-claim-button")

      html = view |> element("#bounty-claim-button") |> render_click()

      assert html =~ "claimed"
      assert has_element?(view, "#bounty-claims")

      bounty = Repo.get!(Bounty, bounty.id)
      assert bounty.status == "claimed"

      claim = Repo.one!(Tarakan.Market.BountyClaim)
      assert claim.account_id == hunter.id
      assert claim.review_task_id
    end
  end

  describe "wanted banners" do
    test "the repository security page shows the banner for its open bounty", %{conn: conn} do
      {bounty, _sponsor, repository} = open_bounty()

      {:ok, view, _html} =
        live(conn, TarakanWeb.RepositoryPaths.repository_security_path(repository))

      assert has_element?(view, "#wanted-banner")

      bounty = Market.get_bounty!(bounty.public_id)
      assert bounty.status == "open"
    end
  end
end
