defmodule ToweropsWeb.Api.MobileController do
  @moduledoc """
  API controller for mobile app data access.

  All endpoints require mobile authentication via bearer token.
  """
  use ToweropsWeb, :controller

  alias Towerops.Alerts
  alias Towerops.Devices
  alias Towerops.Organizations
  alias Towerops.Sites

  @doc """
  GET /api/v1/mobile/organizations

  Returns list of organizations the user has access to.

  Response:
  {
    "organizations": [
      {
        "id": "uuid",
        "name": "Acme Corp",
        "sites_count": 3,
        "device_count": 15,
        "active_alerts_count": 2
      }
    ]
  }
  """
  def list_organizations(conn, _params) do
    user = conn.assigns.current_user

    organizations =
      user.id
      |> Organizations.list_user_organizations()
      |> Enum.map(fn org ->
        %{
          id: org.id,
          name: org.name,
          sites_count: Sites.count_organization_sites(org.id),
          device_count: Devices.count_organization_devices(org.id),
          active_alerts_count: Alerts.count_active_alerts(org.id)
        }
      end)

    json(conn, %{organizations: organizations})
  end

  @doc """
  GET /api/v1/mobile/organizations/:id/sites

  Returns list of sites for an organization.

  Response:
  {
    "sites": [
      {
        "id": "uuid",
        "name": "Main Office",
        "location": "New York, NY",
        "device_count": 5,
        "equipment_down_count": 1
      }
    ]
  }
  """
  def list_sites(conn, %{"organization_id" => org_id}) do
    user = conn.assigns.current_user

    case verify_organization_access(user, org_id) do
      {:ok, _org} ->
        sites =
          org_id
          |> Sites.list_organization_sites()
          |> Enum.map(fn site ->
            %{
              id: site.id,
              name: site.name,
              location: site.location,
              device_count: Devices.count_site_devices(site.id),
              equipment_down_count: Devices.count_site_devices_down(site.id)
            }
          end)

        json(conn, %{sites: sites})

      {:error, :unauthorized} ->
        conn
        |> put_status(:forbidden)
        |> json(%{error: "Access denied to this organization"})
    end
  end

  @doc """
  GET /api/v1/mobile/organizations/:id/devices

  Returns list of devices for an organization with current status.

  Query params:
  - site_id: Filter by site (optional)
  - status: Filter by status: "up", "down", "unknown" (optional)

  Response:
  {
    "device": [
      {
        "id": "uuid",
        "name": "Core Router",
        "ip_address": "192.168.1.1",
        "site_name": "Main Office",
        "status": "up",
        "uptime": "15 days, 4 hours",
        "last_seen_at": "2026-01-15T19:44:25Z"
      }
    ]
  }
  """
  def list_devices(conn, %{"organization_id" => org_id} = params) do
    user = conn.assigns.current_user

    case verify_organization_access(user, org_id) do
      {:ok, _org} ->
        equipment_list =
          org_id
          |> Devices.list_organization_devices(params)
          |> Enum.map(&format_equipment/1)

        json(conn, %{device: equipment_list})

      {:error, :unauthorized} ->
        conn
        |> put_status(:forbidden)
        |> json(%{error: "Access denied to this organization"})
    end
  end

  @doc """
  GET /api/v1/mobile/devices/:id

  Returns detailed device information including interfaces and sensors.

  Response:
  {
    "id": "uuid",
    "name": "Core Router",
    "ip_address": "192.168.1.1",
    "status": "up",
    "uptime": "15 days, 4 hours",
    "site": {"id": "uuid", "name": "Main Office"},
    "interfaces": [...],
    "sensors": [...]
  }
  """
  def get_device(conn, %{"id" => device_id}) do
    user = conn.assigns.current_user

    case Devices.get_device_with_details(device_id) do
      nil ->
        conn
        |> put_status(:not_found)
        |> json(%{error: "Device not found"})

      device ->
        case verify_organization_access(user, device.organization_id) do
          {:ok, _org} ->
            json(conn, format_equipment_details(device))

          {:error, :unauthorized} ->
            conn
            |> put_status(:forbidden)
            |> json(%{error: "Access denied to this device"})
        end
    end
  end

  @doc """
  GET /api/v1/mobile/organizations/:id/alerts

  Returns list of alerts for an organization.

  Query params:
  - severity: Filter by severity: "critical", "warning", "info" (optional)
  - status: Filter by status: "active", "acknowledged", "resolved" (optional)
  - limit: Number of alerts to return (default 50, max 200)

  Response:
  {
    "alerts": [
      {
        "id": "uuid",
        "severity": "critical",
        "status": "active",
        "message": "Device Down: Core Router",
        "equipment_name": "Core Router",
        "device_id": "uuid",
        "occurred_at": "2026-01-15T19:44:25Z"
      }
    ]
  }
  """
  def list_alerts(conn, %{"organization_id" => org_id} = params) do
    user = conn.assigns.current_user

    case verify_organization_access(user, org_id) do
      {:ok, _org} ->
        limit = min(String.to_integer(params["limit"] || "50"), 200)

        alerts =
          org_id
          |> Alerts.list_organization_alerts(Map.put(params, "limit", limit))
          |> Enum.map(&format_alert/1)

        json(conn, %{alerts: alerts})

      {:error, :unauthorized} ->
        conn
        |> put_status(:forbidden)
        |> json(%{error: "Access denied to this organization"})
    end
  end

  # Private helpers

  defp verify_organization_access(user, org_id) do
    if Organizations.user_has_access?(user.id, org_id) do
      {:ok, org_id}
    else
      {:error, :unauthorized}
    end
  end

  defp format_equipment(device) do
    %{
      id: device.id,
      name: device.name,
      ip_address: device.ip_address,
      site_name: device.site && device.site.name,
      status: device.status || "unknown",
      uptime: format_uptime(device),
      last_seen_at: device.last_seen_at
    }
  end

  defp format_equipment_details(device) do
    %{
      id: device.id,
      name: device.name,
      ip_address: device.ip_address,
      status: device.status || "unknown",
      uptime: format_uptime(device),
      site: %{
        id: device.site.id,
        name: device.site.name
      },
      interfaces:
        Enum.map(device.snmp_device.interfaces || [], fn interface ->
          %{
            id: interface.id,
            name: interface.if_name,
            alias: interface.if_alias,
            status: interface.if_oper_status,
            admin_status: interface.if_admin_status,
            speed: interface.if_speed,
            mac_address: interface.if_phys_address
          }
        end),
      sensors:
        Enum.map(device.snmp_device.sensors || [], fn sensor ->
          %{
            id: sensor.id,
            name: sensor.name,
            type: sensor.sensor_type,
            unit: sensor.unit,
            current_value: sensor.current_value,
            status: sensor.status
          }
        end)
    }
  end

  defp format_alert(alert) do
    %{
      id: alert.id,
      status: format_alert_status(alert),
      message: alert.message,
      equipment_name: alert.device && alert.device.name,
      device_id: alert.device_id,
      occurred_at: alert.triggered_at
    }
  end

  defp format_alert_status(alert) do
    cond do
      alert.resolved_at != nil -> "resolved"
      alert.acknowledged_at != nil -> "acknowledged"
      true -> "active"
    end
  end

  defp format_uptime(device) do
    if device.snmp_device && device.snmp_device.sys_uptime do
      timeticks_to_string(device.snmp_device.sys_uptime)
    end
  end

  defp timeticks_to_string(timeticks) do
    seconds = div(timeticks, 100)
    days = div(seconds, 86_400)
    hours = div(rem(seconds, 86_400), 3600)
    minutes = div(rem(seconds, 3600), 60)

    cond do
      days > 0 -> "#{days}d #{hours}h"
      hours > 0 -> "#{hours}h #{minutes}m"
      true -> "#{minutes}m"
    end
  end
end
