defmodule ToweropsWeb.AgentLive.ShowTest do
  use ToweropsWeb.ConnCase

  import Phoenix.LiveViewTest

  alias Towerops.AgentsFixtures

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

    conn =
      conn
      |> log_in_user(user)
      |> put_session(:current_organization_id, organization.id)

    %{conn: conn, user: user, organization: organization}
  end

  defp create_agent(organization_id, name \\ nil) do
    {:ok, agent_token, _raw_token} = AgentsFixtures.agent_token_fixture(organization_id, name)
    agent_token
  end

  describe "mount and display" do
    test "renders agent details page with agent name", %{conn: conn, organization: org} do
      agent = create_agent(org.id, "My Test Agent")

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "My Test Agent"
      assert html =~ "Agent Details"
    end

    test "displays status information", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Status"
      # Agent has nil last_seen_at, so should show "Never connected"
      assert html =~ "Never connected"
    end

    test "displays device count section", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Device"
      # No direct assignments by default
      assert html =~ "0 direct"
    end

    test "displays polling targets section with no devices message", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Polling Targets"
      assert html =~ "No devices assigned"
    end

    test "displays edit link", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Edit Agent"
      assert html =~ ~p"/agents/#{agent.id}/edit"
    end

    test "displays back to agents link", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Back to Agents"
    end

    test "displays timestamps section", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      assert html =~ "Timestamps"
      assert html =~ "Created"
      assert html =~ "Last Updated"
    end
  end

  describe "tab switching" do
    test "switches to debug tab for superuser", %{conn: _conn, organization: _org} do
      user = Towerops.AccountsFixtures.user_fixture()

      user
      |> Ecto.Changeset.change(%{is_superuser: true})
      |> Towerops.Repo.update!()

      {:ok, super_org} = Towerops.Organizations.create_organization(%{name: "Super Org"}, user.id)
      super_agent = create_agent(super_org.id)

      super_conn =
        build_conn()
        |> log_in_user(user)
        |> put_session(:current_organization_id, super_org.id)

      {:ok, view, html} = live(super_conn, ~p"/agents/#{super_agent.id}")

      # Default tab should be overview
      assert html =~ "Overview"
      assert html =~ "Debug Logs"

      # Switch to debug tab
      html = view |> element("button", "Debug Logs") |> render_click()

      assert html =~ "Debug Status"
      assert html =~ "View Debug Logs"
    end

    test "switches back to overview tab", %{conn: _conn, organization: _org} do
      user = Towerops.AccountsFixtures.user_fixture()

      user
      |> Ecto.Changeset.change(%{is_superuser: true})
      |> Towerops.Repo.update!()

      {:ok, super_org} = Towerops.Organizations.create_organization(%{name: "Super Org"}, user.id)
      super_agent = create_agent(super_org.id)

      super_conn =
        build_conn()
        |> log_in_user(user)
        |> put_session(:current_organization_id, super_org.id)

      {:ok, view, _html} = live(super_conn, ~p"/agents/#{super_agent.id}")

      # Switch to debug tab then back to overview
      view |> element("button", "Debug Logs") |> render_click()
      html = view |> element("button", "Overview") |> render_click()

      assert html =~ "Polling Targets"
    end

    test "non-superuser does not see tab navigation", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      refute html =~ "Debug Logs"
    end
  end

  describe "authentication" do
    test "redirects to login when not authenticated" do
      conn = build_conn()

      assert {:error, {:redirect, %{to: to}}} = live(conn, ~p"/agents/#{Ecto.UUID.generate()}")

      assert to =~ "/users/log-in"
    end
  end

  describe "authorization" do
    test "raises when accessing agent from another organization", %{conn: conn} do
      # Create a second user with their own org and agent
      other_user = Towerops.AccountsFixtures.user_fixture()
      {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, other_user.id)
      other_agent = create_agent(other_org.id, "Other Org Agent")

      # The current user should not be able to access this agent
      assert_raise Ecto.NoResultsError, fn ->
        live(conn, ~p"/agents/#{other_agent.id}")
      end
    end

    test "superuser can access agent from any organization" do
      superuser = Towerops.AccountsFixtures.user_fixture()

      superuser
      |> Ecto.Changeset.change(%{is_superuser: true})
      |> Towerops.Repo.update!()

      {:ok, super_org} = Towerops.Organizations.create_organization(%{name: "Super Org"}, superuser.id)

      # Create agent in a different org
      other_user = Towerops.AccountsFixtures.user_fixture()
      {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, other_user.id)
      other_agent = create_agent(other_org.id, "Cross-Org Agent")

      super_conn =
        build_conn()
        |> log_in_user(superuser)
        |> put_session(:current_organization_id, super_org.id)

      {:ok, _view, html} = live(super_conn, ~p"/agents/#{other_agent.id}")

      assert html =~ "Cross-Org Agent"
    end
  end

  describe "superuser actions" do
    test "restart button is visible for superuser" do
      superuser = Towerops.AccountsFixtures.user_fixture()

      superuser
      |> Ecto.Changeset.change(%{is_superuser: true})
      |> Towerops.Repo.update!()

      {:ok, super_org} = Towerops.Organizations.create_organization(%{name: "Super Org"}, superuser.id)
      agent = create_agent(super_org.id)

      super_conn =
        build_conn()
        |> log_in_user(superuser)
        |> put_session(:current_organization_id, super_org.id)

      {:ok, _view, html} = live(super_conn, ~p"/agents/#{agent.id}")

      assert html =~ "Restart"
      assert html =~ "Update"
    end

    test "restart and update buttons are not visible for regular user", %{conn: conn, organization: org} do
      agent = create_agent(org.id)

      {:ok, _view, html} = live(conn, ~p"/agents/#{agent.id}")

      refute html =~ "restart_agent"
      refute html =~ "update_agent"
    end
  end
end
