defmodule TarakanWeb.BountyLive.Show do
  @moduledoc "One contract: target, reward, claims, and sponsor/moderator controls."
  use TarakanWeb, :live_view

  import TarakanWeb.BountyComponents

  alias Tarakan.Market
  alias Tarakan.Market.Bounty
  alias Tarakan.Policy

  @impl true
  def mount(%{"public_id" => public_id}, _session, socket) do
    bounty = Market.get_bounty!(public_id)

    {:ok,
     socket
     |> assign(:page_title, "Contract: #{bounty.title}")
     |> assign(:meta_description, meta_description(bounty))
     |> assign(:canonical_path, ~p"/bounties/#{bounty.public_id}")
     |> assign_bounty(bounty)}
  end

  @impl true
  def handle_event("claim", _params, socket) do
    case Market.claim_bounty(socket.assigns.current_scope, socket.assigns.bounty) do
      {:ok, _claim} ->
        {:noreply,
         socket
         |> put_flash(:info, "Contract claimed - the job is yours for the next two hours.")
         |> reload_bounty()}

      {:error, reason} ->
        {:noreply, put_flash(socket, :error, claim_error_message(reason))}
    end
  end

  def handle_event("cancel", _params, socket) do
    case Market.cancel_bounty(socket.assigns.current_scope, socket.assigns.bounty) do
      {:ok, _bounty} ->
        {:noreply,
         socket
         |> put_flash(:info, "Contract cancelled. Escrowed funds were returned.")
         |> reload_bounty()}

      {:error, reason} ->
        {:noreply, put_flash(socket, :error, cancel_error_message(reason))}
    end
  end

  def handle_event("settle", _params, socket) do
    case Market.settle_bounty(socket.assigns.current_scope, socket.assigns.bounty) do
      {:ok, bounty} ->
        message =
          if bounty.funding == "fiat",
            do: "Contract settled. Payout is pending manual processing.",
            else: "Contract settled. Credits were paid to the winner."

        {:noreply, socket |> put_flash(:info, message) |> reload_bounty()}

      {:error, reason} ->
        {:noreply, put_flash(socket, :error, settle_error_message(reason))}
    end
  end

  def handle_event("mark_paid", _params, socket) do
    case Market.mark_paid(socket.assigns.current_scope, socket.assigns.bounty) do
      {:ok, _bounty} ->
        {:noreply, socket |> put_flash(:info, "Contract marked paid.") |> reload_bounty()}

      {:error, _reason} ->
        {:noreply, put_flash(socket, :error, "The contract could not be marked paid.")}
    end
  end

  defp reload_bounty(socket) do
    assign_bounty(socket, Market.get_bounty!(socket.assigns.bounty.public_id))
  end

  defp assign_bounty(socket, bounty) do
    scope = socket.assigns.current_scope
    account_id = scope && scope.account_id

    claims = Enum.sort_by(bounty.claims, & &1.id, :desc)

    my_claim =
      if account_id, do: Enum.find(claims, &(&1.account_id == account_id)), else: nil

    socket
    |> assign(:bounty, bounty)
    |> assign(:claims, claims)
    |> assign(:claim_count, length(claims))
    |> assign(:my_claim, my_claim)
    |> assign(:sponsor?, account_id != nil and account_id == bounty.sponsor_account_id)
    |> assign(:winner?, account_id != nil and account_id == bounty.winner_account_id)
    |> assign(:moderator?, scope != nil and Policy.moderator?(scope))
    |> assign(:admin?, scope != nil and Policy.admin?(scope))
    |> assign(:can_claim?, can_claim?(scope, bounty))
    |> assign(:can_cancel?, can_cancel?(scope, bounty))
  end

  defp can_claim?(nil, _bounty), do: false

  defp can_claim?(scope, %Bounty{} = bounty) do
    scope.account_id != nil and scope.account_state == "active" and
      bounty.status == "open" and scope.account_id != bounty.sponsor_account_id
  end

  defp can_cancel?(nil, _bounty), do: false

  defp can_cancel?(scope, %Bounty{} = bounty) do
    bounty.status in ["pending_funding", "open"] and bounty.claims == [] and
      (scope.account_id == bounty.sponsor_account_id or Policy.moderator?(scope))
  end

  defp meta_description(bounty) do
    "#{amount_label(bounty)} contract on #{target_label(bounty)}: #{bounty.title}"
    |> String.replace(~r/\s+/, " ")
    |> String.slice(0, 160)
  end

  defp claim_error_message(:own_bounty), do: "You cannot claim your own contract."
  defp claim_error_message(:not_open), do: "This contract is no longer open."
  defp claim_error_message(:claim_limit), do: "You already hold too many active claims."
  defp claim_error_message(:unauthorized), do: "Your account cannot claim contracts."
  defp claim_error_message(_reason), do: "The contract could not be claimed. Try again shortly."

  defp cancel_error_message(:has_claims), do: "A contract with claims cannot be cancelled."
  defp cancel_error_message(:invalid_state), do: "This contract can no longer be cancelled."
  defp cancel_error_message(:unauthorized), do: "You cannot cancel this contract."

  defp cancel_error_message(_reason),
    do: "The contract could not be cancelled. Try again shortly."

  defp settle_error_message(:no_winning_claim), do: "No submitted or accepted claim to settle."
  defp settle_error_message(:invalid_state), do: "This contract is not awaiting settlement."
  defp settle_error_message(_reason), do: "The contract could not be settled. Try again shortly."

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope} current_path={assigns[:current_path]}>
      <Layouts.page width={:focused}>
        <div id={"bounty-poster-#{@bounty.public_id}"} class="border-2 border-strong">
          <div class="flex items-center justify-between border-b-2 border-strong bg-panel px-5 py-3">
            <.notch_badge class="bg-signal text-ground">Contract</.notch_badge>
            <span
              id="bounty-status"
              class="font-mono text-[10px] uppercase tracking-[0.12em] text-ink-faint"
            >
              {status_label(@bounty.status)}
            </span>
          </div>

          <div class="px-5 py-6">
            <p id="bounty-amount" class="font-display text-5xl font-medium leading-none text-signal">
              {amount_label(@bounty)}
            </p>
            <h1 class="mt-4 font-display text-2xl font-medium uppercase leading-tight tracking-[0.02em] text-ink">
              {@bounty.title}
            </h1>

            <dl class="mt-5 space-y-2 border-y-2 border-rule py-4 font-mono text-xs text-ink-muted">
              <div class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Target</dt>
                <dd class="text-right">
                  <%= if path = target_path(@bounty) do %>
                    <.link navigate={path} class="text-signal hover:underline">
                      {target_label(@bounty)}
                    </.link>
                  <% else %>
                    {target_label(@bounty)}
                  <% end %>
                </dd>
              </div>
              <div class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Sponsor</dt>
                <dd>
                  <.link
                    navigate={~p"/#{@bounty.sponsor_account.handle}"}
                    class="text-signal hover:underline"
                  >
                    @{@bounty.sponsor_account.handle}
                  </.link>
                </dd>
              </div>
              <div class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Funding</dt>
                <dd>{if @bounty.funding == "fiat", do: "card escrow", else: "credits"}</dd>
              </div>
              <div :if={@bounty.expires_at} class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Expires</dt>
                <dd>{Calendar.strftime(@bounty.expires_at, "%Y-%m-%d")}</dd>
              </div>
              <div class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Claims</dt>
                <dd>{@claim_count}</dd>
              </div>
              <div :if={@bounty.winner_account} class="flex justify-between gap-4">
                <dt class="uppercase tracking-[0.12em] text-ink-faint">Winner</dt>
                <dd>
                  <.link
                    navigate={~p"/#{@bounty.winner_account.handle}"}
                    class="text-signal hover:underline"
                  >
                    @{@bounty.winner_account.handle}
                  </.link>
                </dd>
              </div>
            </dl>

            <p class="mt-5 whitespace-pre-wrap text-sm leading-6 text-ink">{@bounty.description}</p>

            <div
              :if={@winner? and @bounty.status == "payout_pending"}
              class="mt-5 border-2 border-rule bg-panel px-4 py-3 text-xs leading-5 text-ink-muted"
            >
              Payout pending - the platform processes fiat payouts manually. You'll be
              contacted at your account email.
            </div>
            <div
              :if={@sponsor? and @bounty.status == "payout_pending"}
              class="mt-5 border-2 border-rule bg-panel px-4 py-3 text-xs leading-5 text-ink-muted"
            >
              Payout pending - escrowed funds are being released to the winner.
            </div>

            <div class="mt-6 flex flex-wrap items-center gap-3">
              <button
                :if={@can_claim?}
                id="bounty-claim-button"
                type="button"
                phx-click="claim"
                class="cursor-pointer border-2 border-signal px-5 py-2 font-display text-xs uppercase tracking-[0.12em] text-signal transition hover:bg-signal hover:text-ground"
              >
                Claim this contract
              </button>
              <.link
                :if={not @can_claim? and @bounty.status == "open" and @current_scope == nil}
                id="bounty-login-to-claim"
                navigate={~p"/accounts/log-in"}
                class="border-2 border-signal px-5 py-2 font-display text-xs uppercase tracking-[0.12em] text-signal transition hover:bg-signal hover:text-ground"
              >
                Log in to claim
              </.link>
              <button
                :if={@can_cancel?}
                id="bounty-cancel-button"
                type="button"
                phx-click="cancel"
                data-confirm="Cancel this contract? Escrowed funds will be returned."
                class="cursor-pointer border border-strong px-5 py-2 font-display text-xs uppercase tracking-[0.12em] text-ink-muted transition hover:border-ink hover:text-ink"
              >
                Cancel contract
              </button>
              <button
                :if={@moderator? and @bounty.status == "claimed"}
                id="bounty-settle-button"
                type="button"
                phx-click="settle"
                class="cursor-pointer border-2 border-signal px-5 py-2 font-display text-xs uppercase tracking-[0.12em] text-signal transition hover:bg-signal hover:text-ground"
              >
                Settle contract
              </button>
              <button
                :if={@admin? and @bounty.status == "payout_pending"}
                id="bounty-mark-paid-button"
                type="button"
                phx-click="mark_paid"
                class="cursor-pointer border-2 border-signal px-5 py-2 font-display text-xs uppercase tracking-[0.12em] text-signal transition hover:bg-signal hover:text-ground"
              >
                Mark paid
              </button>
            </div>
          </div>
        </div>

        <section :if={@claims != []} id="bounty-claims" class="mt-8">
          <h2 class="font-mono text-[11px] uppercase tracking-[0.12em] text-ink-faint">
            Claims
          </h2>
          <ul class="mt-3 divide-y divide-rule border-2 border-strong">
            <li
              :for={claim <- @claims}
              id={"bounty-claim-#{claim.id}"}
              class="flex items-center justify-between gap-4 px-4 py-3"
            >
              <span class="font-mono text-xs text-ink">
                @{claim.account.handle}
                <span :if={claim.review_task} class="text-ink-faint">
                  ·
                  <.link
                    navigate={~p"/jobs/#{claim.review_task.id}"}
                    class="text-signal hover:underline"
                  >job</.link>
                </span>
              </span>
              <span class="font-mono text-[10px] uppercase tracking-[0.12em] text-ink-muted">
                {claim.status}
              </span>
            </li>
          </ul>
        </section>

        <p
          :if={@my_claim && @my_claim.status in ["claimed", "submitted"]}
          class="mt-6 text-xs leading-5 text-ink-muted"
        >
          Your claim is backed by
          <.link
            navigate={~p"/jobs/#{@my_claim.review_task.id}"}
            class="font-semibold text-signal hover:underline"
          >
            this job
          </.link>
          - submit your work there. Settlement follows acceptance.
        </p>
      </Layouts.page>
    </Layouts.app>
    """
  end
end
