internal/dashboard/frontend/src/composables/useChartStats.ts

import { getCountry } from "src/countries";
import type { ItemList } from "src/types";
import { sidebarLimit } from "utils/chart";
import { type ChartDataPoint } from "utils/filters";
import { computed, type Ref } from "vue";

export function useChartStats(
  chartData: Ref<ChartDataPoint[]>,
  xRange: Ref<string[] | undefined>,
  yRange: Ref<string[] | undefined>,
  latRange?: Ref<string[] | undefined>,
  lonRange?: Ref<string[] | undefined>,
) {
  const effectiveData = computed(() => {
    let data = chartData.value;

    if (xRange.value && xRange.value.length === 2) {
      const minX = new Date(xRange.value[0]!).getTime();
      const maxX = new Date(xRange.value[1]!).getTime();
      data = data.filter((d) => {
        const t = d.time.getTime();
        return t >= minX && t <= maxX;
      });
    }

    if (yRange.value && yRange.value.length === 2) {
      const minY = parseFloat(yRange.value[0]!);
      const maxY = parseFloat(yRange.value[1]!);
      data = data.filter((d) => {
        return d.dst_port >= minY && d.dst_port <= maxY;
      });
    }

    if (latRange?.value && latRange.value.length === 2) {
      const minLat = Math.min(
        parseFloat(latRange.value[0]!),
        parseFloat(latRange.value[1]!),
      );
      const maxLat = Math.max(
        parseFloat(latRange.value[0]!),
        parseFloat(latRange.value[1]!),
      );
      data = data.filter((d) => {
        if (d.latitude === undefined) return false;
        return d.latitude >= minLat && d.latitude <= maxLat;
      });
    }

    if (lonRange?.value && lonRange.value.length === 2) {
      const minLon = Math.min(
        parseFloat(lonRange.value[0]!),
        parseFloat(lonRange.value[1]!),
      );
      const maxLon = Math.max(
        parseFloat(lonRange.value[0]!),
        parseFloat(lonRange.value[1]!),
      );
      data = data.filter((d) => {
        if (d.longitude === undefined) return false;
        return d.longitude >= minLon && d.longitude <= maxLon;
      });
    }

    return data;
  });

  const ipCounts = computed(() => {
    const counts: Record<string, number> = {};
    effectiveData.value.forEach((point: ChartDataPoint) => {
      counts[point.remote_addr] = (counts[point.remote_addr] || 0) + 1;
    });

    return Object.entries(counts)
      .map(([value, count]) => ({ value, count }))
      .sort((a, b) => b.count - a.count)
      .slice(0, sidebarLimit);
  });

  const portCounts = computed<ItemList[]>(() => {
    const counts: Record<number, number> = {};
    effectiveData.value.forEach((point: ChartDataPoint) => {
      counts[point.dst_port] = (counts[point.dst_port] || 0) + 1;
    });
    delete counts[-1];

    return Object.entries(counts)
      .map(([value, count]) => ({ value: Number(value), count }))
      .sort((a, b) => b.count - a.count)
      .slice(0, sidebarLimit);
  });

  const countryCounts = computed<ItemList[]>(() => {
    const counts: Record<string, number> = {};
    effectiveData.value.forEach((point: ChartDataPoint) => {
      const country = point.country || "Unknown";
      counts[country] = (counts[country] || 0) + 1;
    });

    return Object.entries(counts)
      .map(([value, count]) => {
        const country = getCountry(value);
        return {
          value,
          count,
          label: `${country.flag} ${country.name}`,
        };
      })
      .sort((a, b) => b.count - a.count)
      .slice(0, sidebarLimit);
  });

  return {
    ipCounts,
    portCounts,
    countryCounts,
  };
}