defmodule ToweropsWeb.AgentLive.Helpers do @moduledoc """ Shared helper functions for agent LiveView modules. """ @doc """ Determines the agent's status based on last_seen_at timestamp. Returns a tuple of {status_atom, status_label} where status_atom is: - :online - Last seen within 2 minutes - :warning - Last seen between 2-5 minutes - :offline - Last seen more than 5 minutes ago - :never - Never connected """ def agent_status(agent_token) do case agent_token.last_seen_at do nil -> {:never, "Never connected"} last_seen -> seconds_ago = DateTime.diff(DateTime.utc_now(), last_seen, :second) cond do seconds_ago < 120 -> {:online, "Online"} seconds_ago < 300 -> {:warning, "Warning"} true -> {:offline, "Offline"} end end end @doc """ Returns Tailwind CSS classes for status badge background and text colors. """ def status_badge_class(status) do case status do :online -> "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300" :warning -> "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300" :offline -> "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300" :never -> "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-300" end end @doc """ Returns Tailwind CSS classes for status indicator dot. Online status includes animation. """ def status_dot_class(status) do case status do :online -> "bg-green-600 dark:bg-green-400 animate-pulse" :warning -> "bg-yellow-600 dark:bg-yellow-400" :offline -> "bg-red-600 dark:bg-red-400" :never -> "bg-gray-400 dark:bg-gray-600" end end @doc """ Formats a DateTime into a human-readable "time ago" string. Returns strings like "5s ago", "3m ago", "2h ago", or "5d ago". Delegates to ToweropsWeb.TimeHelpers.format_time_ago/1. """ defdelegate format_last_seen(datetime), to: ToweropsWeb.TimeHelpers, as: :format_time_ago @doc """ Formats uptime in seconds to a human-readable string. Returns strings like "2h 34m" or "5d 3h". """ def format_uptime(uptime_seconds) when is_integer(uptime_seconds) do days = div(uptime_seconds, 86_400) hours = div(rem(uptime_seconds, 86_400), 3600) minutes = div(rem(uptime_seconds, 3600), 60) cond do days > 0 -> "#{days}d #{hours}h" hours > 0 -> "#{hours}h #{minutes}m" true -> "#{minutes}m" end end def format_uptime(_), do: "Unknown" @doc """ Formats a DateTime into a full date and time string. Returns strings like "Jan 15, 2026 at 2:34 PM EST". Delegates to ToweropsWeb.TimeHelpers.format_datetime/2. """ def format_datetime(datetime, timezone \\ "UTC") do ToweropsWeb.TimeHelpers.format_datetime(datetime, timezone) end @doc """ Formats a DateTime into a short date string. Returns strings like "Jan 15, 2026". Delegates to ToweropsWeb.TimeHelpers.format_date/2. """ def format_date(datetime, timezone \\ "UTC") do ToweropsWeb.TimeHelpers.format_date(datetime, timezone) end @doc """ Formats a DateTime into a relative time with full datetime in parentheses. Returns strings like "5m ago (Jan 15, 2026 at 2:34 PM EST)". """ def format_last_seen_with_date(datetime, timezone \\ "UTC") def format_last_seen_with_date(nil, _timezone), do: "Never" def format_last_seen_with_date(datetime, timezone) do relative = format_last_seen(datetime) full = format_datetime(datetime, timezone) "#{relative} (#{full})" end @doc """ Formats agent version for display. Handles both legacy semver ("1.2.3") and RFC 3339 timestamp ("2026-02-09T14:30:00Z") formats. Timestamps show the full value with a human-readable date, e.g. "2026-02-09T14:30:00Z (Feb 9, 2026)". """ def format_agent_version(version) when is_binary(version) do if String.match?(version, ~r/^\d{4}-\d{2}-\d{2}T/) do version else "v#{version}" end end def format_agent_version(_), do: nil end