defmodule ToweropsWeb.AgentLiveTest do
  use ToweropsWeb.ConnCase

  import Ecto.Query
  import Phoenix.LiveViewTest

  alias Towerops.Agents

  setup :register_and_log_in_user

  setup %{user: user} do
    {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)

    %{organization: organization}
  end

  describe "Index" do
    test "lists all agent tokens", %{conn: conn, organization: organization} do
      {:ok, _agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "Remote Agents"
      assert html =~ "Agent 1"
    end

    test "displays empty state when no agents", %{conn: conn, organization: organization} do
      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "No agents"
      assert html =~ "Get started by creating your first remote agent"
    end

    test "creates new agent and shows token modal", %{conn: conn, organization: organization} do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      html =
        view
        |> form("#new-agent-form form", %{name: "Test Agent"})
        |> render_submit()

      assert html =~ "Agent Setup Instructions"
      assert html =~ "Test Agent"
      assert html =~ "Authentication Token"
    end

    test "deletes agent", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      html =
        view
        |> element("button", "Delete")
        |> render_click()

      assert html =~ "Agent deleted successfully"

      # Verify agent was actually deleted
      assert is_nil(Towerops.Repo.get(Agents.AgentToken, agent_token.id))
    end

    test "closes token modal", %{conn: conn, organization: organization} do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      # Create agent to show modal
      view
      |> form("#new-agent-form form", %{name: "Test Agent"})
      |> render_submit()

      # Close modal
      html =
        view
        |> element("button", "I've Saved the Token")
        |> render_click()

      refute html =~ "Agent Created Successfully"
    end

    test "requires authentication", %{organization: organization} do
      conn = build_conn()
      {:error, redirect} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert {:redirect, %{to: path}} = redirect
      assert path == ~p"/users/log-in"
    end

    test "displays agent with warning status", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      # Update last_seen_at to 3 minutes ago (warning status)
      three_minutes_ago = DateTime.add(DateTime.utc_now(), -180, :second)

      Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1")

      Towerops.Repo.update_all(
        from(t in Agents.AgentToken, where: t.id == ^agent_token.id),
        set: [last_seen_at: three_minutes_ago]
      )

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "Warning"
      assert html =~ "3m ago"
    end

    test "displays agent with offline status", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      # Update last_seen_at to 10 minutes ago (offline status)
      ten_minutes_ago = DateTime.add(DateTime.utc_now(), -600, :second)

      Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1")

      Towerops.Repo.update_all(
        from(t in Agents.AgentToken, where: t.id == ^agent_token.id),
        set: [last_seen_at: ten_minutes_ago]
      )

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "Offline"
      assert html =~ "10m ago"
    end

    test "displays agent last seen time in hours", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      # Update last_seen_at to 2 hours ago
      two_hours_ago = DateTime.add(DateTime.utc_now(), -7200, :second)

      Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1")

      Towerops.Repo.update_all(
        from(t in Agents.AgentToken, where: t.id == ^agent_token.id),
        set: [last_seen_at: two_hours_ago]
      )

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "2h ago"
    end

    test "displays agent last seen time in days", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1")

      # Update last_seen_at to 2 days ago
      two_days_ago = DateTime.add(DateTime.utc_now(), -172_800, :second)

      Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1")

      Towerops.Repo.update_all(
        from(t in Agents.AgentToken, where: t.id == ^agent_token.id),
        set: [last_seen_at: two_days_ago]
      )

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents")

      assert html =~ "2d ago"
    end
  end

  describe "Edit" do
    test "loads edit page with existing agent name", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Old Agent Name")

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")

      assert html =~ "Edit Agent"
      assert html =~ "Old Agent Name"
      assert html =~ "Update the agent name"
    end

    test "validates empty name shows error on submit", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Test Agent")

      {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")

      html =
        view
        |> form("#edit-agent-form", agent_token: %{name: ""})
        |> render_submit()

      assert html =~ "can&#39;t be blank"

      # Verify agent was not updated
      agent = Agents.get_agent_token!(agent_token.id)
      assert agent.name == "Test Agent"
    end

    test "successful save updates agent and redirects to show page", %{
      conn: conn,
      organization: organization
    } do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Old Name")

      {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")

      view
      |> form("#edit-agent-form", agent_token: %{name: "New Name"})
      |> render_submit()

      # Verify redirect to show page with flash message
      assert_redirect(view, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}")

      # Verify agent was updated
      updated_agent = Agents.get_agent_token!(agent_token.id)
      assert updated_agent.name == "New Name"
    end

    test "cancel button navigates back to show page", %{conn: conn, organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Test Agent")

      {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")

      assert html =~ "Cancel"

      # Find cancel link and verify it points to show page
      assert html =~
               ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}"
    end

    test "requires authentication", %{organization: organization} do
      {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Test Agent")

      conn = build_conn()
      {:error, redirect} = live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")

      assert {:redirect, %{to: path}} = redirect
      assert path == ~p"/users/log-in"
    end

    test "verifies agent belongs to organization", %{conn: conn, organization: organization, user: user} do
      # Create another organization
      {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, user.id)
      {:ok, agent_token, _token} = Agents.create_agent_token(other_org.id, "Other Agent")

      # Try to edit agent from other organization
      assert_raise Ecto.NoResultsError, fn ->
        live(conn, ~p"/orgs/#{organization.slug}/agents/#{agent_token.id}/edit")
      end
    end
  end
end
