defmodule ToweropsWeb.Api.AccountDataController do
  @moduledoc """
  API controller for GDPR Right to Access - allows users to download all their data in JSON format
  """
  use ToweropsWeb, :controller

  alias Towerops.Admin
  alias Towerops.Admin.AuditLogger
  alias Towerops.Alerts
  alias Towerops.Devices
  alias Towerops.Organizations

  @doc """
  Returns all user data in JSON format (GDPR Right to Access compliance)
  """
  def show(conn, _params) do
    user = conn.assigns.current_scope.user

    # Log the data export for audit trail
    AuditLogger.log_user_data_exported(conn, user.id)

    # Gather all user data
    data = %{
      profile: build_profile_data(user),
      organizations: build_organizations_data(user),
      devices: build_devices_data(user),
      alerts: build_alerts_data(user),
      audit_logs: build_audit_logs_data(user),
      export_info: %{
        exported_at: DateTime.utc_now(),
        format: "JSON",
        gdpr_article: "Article 15 - Right to Access"
      }
    }

    conn
    |> put_resp_content_type("application/json")
    |> put_resp_header(
      "content-disposition",
      "attachment; filename=\"towerops-data-#{user.id}-#{DateTime.to_unix(DateTime.utc_now())}.json\""
    )
    |> json(data)
  end

  # Build profile data
  defp build_profile_data(user) do
    %{
      id: user.id,
      email: user.email,
      first_name: user.first_name,
      last_name: user.last_name,
      timezone: user.timezone,
      is_superuser: user.is_superuser,
      confirmed_at: user.confirmed_at,
      inserted_at: user.inserted_at,
      updated_at: user.updated_at
    }
  end

  # Build organizations data
  defp build_organizations_data(user) do
    user.id
    |> Organizations.list_user_organizations()
    |> Enum.map(fn org ->
      # Organization has the user's membership preloaded (only their membership)
      [membership] = org.memberships

      %{
        id: org.id,
        name: org.name,
        slug: org.slug,
        role: if(membership.role == :owner, do: "owner", else: "member"),
        inserted_at: org.inserted_at,
        updated_at: org.updated_at
      }
    end)
  end

  # Build devices data
  defp build_devices_data(user) do
    org_ids =
      user.id
      |> Organizations.list_user_organizations()
      |> Enum.map(& &1.id)

    if Enum.empty?(org_ids) do
      []
    else
      org_ids
      |> Devices.list_devices_for_organizations()
      |> Enum.map(fn device ->
        %{
          id: device.id,
          name: device.name,
          ip_address: device.ip_address,
          snmp_community: "[REDACTED]",
          monitoring_enabled: device.monitoring_enabled,
          snmp_enabled: device.snmp_enabled,
          status: device.status,
          organization: %{
            id: device.organization_id,
            name: device.organization.name
          },
          site: %{
            id: device.site_id,
            name: device.site.name
          },
          inserted_at: device.inserted_at,
          updated_at: device.updated_at
        }
      end)
    end
  end

  # Build alerts data (last 90 days)
  defp build_alerts_data(user) do
    org_ids =
      user.id
      |> Organizations.list_user_organizations()
      |> Enum.map(& &1.id)

    if Enum.empty?(org_ids) do
      []
    else
      ninety_days_ago = DateTime.add(DateTime.utc_now(), -90, :day)

      org_ids
      |> Alerts.list_alerts_for_organizations(since: ninety_days_ago)
      |> Enum.map(fn alert ->
        %{
          id: alert.id,
          alert_type: alert.alert_type,
          message: alert.message,
          triggered_at: alert.triggered_at,
          resolved_at: alert.resolved_at,
          acknowledged_at: alert.acknowledged_at,
          device: %{
            id: alert.device_id,
            name: alert.device.name
          },
          inserted_at: alert.inserted_at
        }
      end)
    end
  end

  # Build audit logs data
  defp build_audit_logs_data(user) do
    user.id
    |> Admin.list_audit_logs_for_user(limit: 1000)
    |> Enum.map(fn log ->
      %{
        id: log.id,
        action: log.action,
        actor_email: if(log.superuser, do: log.superuser.email),
        target_user_id: log.target_user_id,
        metadata: log.metadata,
        ip_address: log.ip_address,
        inserted_at: log.inserted_at
      }
    end)
  end
end
