defmodule Towerops.Dashboard do
  @moduledoc """
  Aggregates data from multiple contexts for the command center dashboard.
  """

  alias Towerops.Alerts
  alias Towerops.Devices
  alias Towerops.Gaiia
  alias Towerops.Gaiia.ImpactAnalysis
  alias Towerops.Preseem
  alias Towerops.Preseem.Insights
  alias Towerops.Sites

  @doc "Returns a complete dashboard summary for an organization."
  def get_dashboard_summary(organization_id) do
    status_counts = Devices.get_device_status_counts(organization_id)
    total_devices = status_counts |> Map.values() |> Enum.sum()
    active_alerts = Alerts.list_organization_active_alerts(organization_id)
    subscriber_totals = Gaiia.get_org_subscriber_totals(organization_id)
    insight_counts = Insights.count_active_by_urgency(organization_id)

    %{
      health_score: compute_health_score(organization_id),
      devices: %{
        total: total_devices,
        up: Map.get(status_counts, :up, 0),
        down: Map.get(status_counts, :down, 0),
        unknown: Map.get(status_counts, :unknown, 0)
      },
      alerts: %{
        active_count: length(active_alerts)
      },
      subscribers: %{
        total: subscriber_totals.total_subscribers,
        total_mrr: subscriber_totals.total_mrr
      },
      insights: insight_counts
    }
  end

  @doc """
  Compute a weighted 0-100 health score for an organization.

  Weights:
  - Device uptime % (40%)
  - Response time health (20%) - currently based on device status
  - Critical alert penalty (20%)
  - Preseem QoE average (10%, skipped if unavailable)
  - Agent online % (10%, skipped if no agents)

  Unavailable components have their weight redistributed proportionally.
  """
  def compute_health_score(organization_id) do
    status_counts = Devices.get_device_status_counts(organization_id)
    total = status_counts |> Map.values() |> Enum.sum()

    if total == 0 do
      100
    else
      up = Map.get(status_counts, :up, 0)
      down = Map.get(status_counts, :down, 0)
      active_alerts = Alerts.list_organization_active_alerts(organization_id)

      # Device uptime percentage (0.0-1.0)
      uptime_ratio = up / total

      # Response time health - approximate from up/unknown ratio
      responsive_ratio = (total - down) / total

      # Alert penalty - each alert reduces score, capped at full penalty
      alert_penalty = min(length(active_alerts) * 0.1, 1.0)
      alert_score = 1.0 - alert_penalty

      # Weighted score (redistribute Preseem/Agent weights to core metrics)
      # Base weights: uptime 40%, response 20%, alerts 20%, preseem 10%, agents 10%
      # Without preseem/agents: uptime 50%, response 25%, alerts 25%
      score =
        uptime_ratio * 50.0 +
          responsive_ratio * 25.0 +
          alert_score * 25.0

      round(score)
    end
  end

  @doc "Returns subscriber summary for the org from Gaiia data."
  def get_org_subscriber_summary(organization_id) do
    totals = Gaiia.get_org_subscriber_totals(organization_id)

    %{
      total: totals.total_subscribers,
      total_mrr: totals.total_mrr
    }
  end

  @doc "Returns per-site summaries with device counts, alerts, and subscriber data."
  def list_site_summaries(organization_id) do
    sites = Sites.list_organization_sites(organization_id)

    Enum.map(sites, fn site ->
      device_count = Devices.count_site_devices(site.id)
      down_count = Devices.count_site_devices_down(site.id)
      gaiia_summary = Gaiia.get_site_subscriber_summary(site.id)

      %{
        site_id: site.id,
        name: site.name,
        device_count: device_count,
        devices_down: down_count,
        subscribers: if(gaiia_summary, do: gaiia_summary.account_count),
        mrr: if(gaiia_summary, do: gaiia_summary.total_mrr)
      }
    end)
  end

  @doc """
  Returns aggregate impact summary for current outages.

  Shows total subscribers affected by down devices, total MRR at risk,
  and number of sites with outages.
  """
  def get_impact_summary(organization_id) do
    down_devices = Devices.list_organization_devices(organization_id, %{"status" => "down"})

    # Compute impact for each down device
    impacts =
      Enum.map(down_devices, fn device ->
        ImpactAnalysis.analyze_device_impact(organization_id, device.id)
      end)

    # Aggregate — count unique sites with outages
    sites_with_outages =
      down_devices
      |> Enum.map(& &1.site_id)
      |> Enum.reject(&is_nil/1)
      |> Enum.uniq()
      |> length()

    total_subscribers = impacts |> Enum.map(& &1.total_subscribers) |> Enum.sum()

    total_mrr =
      impacts
      |> Enum.map(& &1.total_mrr)
      |> Enum.reduce(Decimal.new("0"), &Decimal.add/2)

    %{
      subscribers_affected: total_subscribers,
      mrr_at_risk: total_mrr,
      sites_with_outages: sites_with_outages,
      down_device_count: length(down_devices)
    }
  end

  @doc """
  Returns down devices enriched with Gaiia subscriber impact, Preseem QoE data,
  site info, and outage duration. Sorted by MRR impact descending.
  """
  def list_active_incidents(organization_id) do
    down_devices = Devices.list_organization_devices(organization_id, %{"status" => "down"})
    now = DateTime.utc_now()

    incidents =
      Enum.map(down_devices, fn device ->
        impact = ImpactAnalysis.analyze_device_impact(organization_id, device.id)
        preseem_ap = Preseem.get_access_point_for_device(device.id)

        duration_seconds =
          if device.last_status_change_at do
            DateTime.diff(now, device.last_status_change_at, :second)
          else
            nil
          end

        %{
          device_id: device.id,
          device_name: device.name,
          site_id: device.site_id,
          site_name: if(device.site, do: device.site.name),
          duration_seconds: duration_seconds,
          subscribers_affected: impact.total_subscribers,
          mrr_at_risk: impact.total_mrr,
          qoe_score: if(preseem_ap, do: preseem_ap.qoe_score),
          triggered_at: device.last_status_change_at
        }
      end)

    Enum.sort_by(incidents, & &1.mrr_at_risk, {:desc, Decimal})
  end

  @doc """
  Enhanced site summaries with impact data from currently-down devices,
  MRR at risk, average QoE score, and site health score.
  """
  def get_site_impact_summaries(organization_id) do
    sites = Sites.list_organization_sites(organization_id)

    Enum.map(sites, fn site ->
      device_count = Devices.count_site_devices(site.id)
      down_count = Devices.count_site_devices_down(site.id)
      gaiia_summary = Gaiia.get_site_subscriber_summary(site.id)

      # Get impact from down devices at this site
      down_devices = Devices.list_organization_devices(organization_id, %{"status" => "down", "site_id" => site.id})

      {subscribers_affected, mrr_at_risk} =
        if down_count > 0 do
          impacts =
            Enum.map(down_devices, fn device ->
              ImpactAnalysis.analyze_device_impact(organization_id, device.id)
            end)

          subs = impacts |> Enum.map(& &1.total_subscribers) |> Enum.sum()
          mrr = impacts |> Enum.map(& &1.total_mrr) |> Enum.reduce(Decimal.new("0"), &Decimal.add/2)
          {subs, mrr}
        else
          {0, Decimal.new("0")}
        end

      # Get average QoE from Preseem for devices at this site
      site_devices = Devices.list_site_devices(site.id)

      qoe_scores =
        site_devices
        |> Enum.map(fn d -> Preseem.get_access_point_for_device(d.id) end)
        |> Enum.reject(&is_nil/1)
        |> Enum.map(& &1.qoe_score)
        |> Enum.reject(&is_nil/1)

      avg_qoe =
        if qoe_scores != [] do
          Enum.sum(qoe_scores) / length(qoe_scores)
        end

      # Site health: green (all up), yellow (some issues), red (devices down)
      site_health =
        cond do
          down_count > 0 -> :red
          avg_qoe && avg_qoe < 7.0 -> :yellow
          true -> :green
        end

      %{
        site_id: site.id,
        name: site.name,
        device_count: device_count,
        devices_down: down_count,
        subscribers: if(gaiia_summary, do: gaiia_summary.account_count),
        mrr: if(gaiia_summary, do: gaiia_summary.total_mrr),
        subscribers_affected: subscribers_affected,
        mrr_at_risk: mrr_at_risk,
        avg_qoe: avg_qoe,
        site_health: site_health
      }
    end)
  end

  @doc "Returns a summary for a single site."
  def get_site_summary(site_id) do
    device_count = Devices.count_site_devices(site_id)
    down_count = Devices.count_site_devices_down(site_id)
    alert_count = Alerts.count_site_active_alerts(site_id)
    gaiia_summary = Gaiia.get_site_subscriber_summary(site_id)

    %{
      device_count: device_count,
      devices_down: down_count,
      alert_count: alert_count,
      subscribers: if(gaiia_summary, do: gaiia_summary.account_count),
      mrr: if(gaiia_summary, do: gaiia_summary.total_mrr)
    }
  end
end
