import { useMemo, useState } from "react"
import { useStore } from "@nanostores/react"
import type { ChartConfig } from "@/components/ui/chart"
import type { ChartData, SystemStats, SystemStatsRecord } from "@/types"
import type { DataPoint } from "./area-chart"
import { $containerFilter } from "@/lib/stores"

/** Chart configurations for CPU, memory, and network usage charts */
export interface ContainerChartConfigs {
	cpu: ChartConfig
	memory: ChartConfig
	network: ChartConfig
}

/**
 * Generates chart configurations for container metrics visualization
 * @param containerData - Array of container statistics data points
 * @returns Chart configurations for CPU, memory, and network metrics
 */
export function useContainerChartConfigs(containerData: ChartData["containerData"]): ContainerChartConfigs {
	return useMemo(() => {
		const configs = {
			cpu: {} as ChartConfig,
			memory: {} as ChartConfig,
			network: {} as ChartConfig,
		}

		// Aggregate usage metrics for each container
		const totalUsage = {
			cpu: new Map<string, number>(),
			memory: new Map<string, number>(),
			network: new Map<string, number>(),
		}

		// Process each data point to calculate totals
		for (let i = 0; i < containerData.length; i++) {
			const stats = containerData[i]
			const containerNames = Object.keys(stats)

			for (let j = 0; j < containerNames.length; j++) {
				const containerName = containerNames[j]
				// Skip metadata field
				if (containerName === "created") {
					continue
				}

				const containerStats = stats[containerName]
				if (!containerStats) {
					continue
				}

				// Accumulate metrics for CPU, memory, and network
				const currentCpu = totalUsage.cpu.get(containerName) ?? 0
				const currentMemory = totalUsage.memory.get(containerName) ?? 0
				const currentNetwork = totalUsage.network.get(containerName) ?? 0
				const sentBytes = containerStats.b?.[0] ?? (containerStats.ns ?? 0) * 1024 * 1024
				const recvBytes = containerStats.b?.[1] ?? (containerStats.nr ?? 0) * 1024 * 1024

				totalUsage.cpu.set(containerName, currentCpu + (containerStats.c ?? 0))
				totalUsage.memory.set(containerName, currentMemory + (containerStats.m ?? 0))
				totalUsage.network.set(containerName, currentNetwork + sentBytes + recvBytes)
			}
		}

		// Generate chart configurations for each metric type
		Object.entries(totalUsage).forEach(([chartType, usageMap]) => {
			const sortedContainers = Array.from(usageMap.entries()).sort(([, a], [, b]) => b - a)
			const chartConfig = {} as Record<string, { label: string; color: string }>
			const count = sortedContainers.length

			// Generate colors for each container
			for (let i = 0; i < count; i++) {
				const [containerName] = sortedContainers[i]
				const hue = ((i * 360) / count) % 360
				chartConfig[containerName] = {
					label: containerName,
					color: `hsl(${hue}, var(--chart-saturation), var(--chart-lightness))`,
				}
			}

			configs[chartType as keyof typeof configs] = chartConfig
		})

		return configs
	}, [containerData])
}

/** Sets the correct width of the y axis in recharts based on the longest label */
export function useYAxisWidth() {
	const [yAxisWidth, setYAxisWidth] = useState(0)
	let maxChars = 0
	let timeout: ReturnType<typeof setTimeout>
	function updateYAxisWidth(str: string) {
		if (str.length > maxChars) {
			maxChars = str.length
			const div = document.createElement("div")
			div.className = "text-xs tabular-nums tracking-tighter table sr-only"
			div.innerHTML = str
			clearTimeout(timeout)
			timeout = setTimeout(() => {
				document.body.appendChild(div)
				const width = div.offsetWidth + 20 
				if (width > yAxisWidth) {
					setYAxisWidth(width)
				}
				document.body.removeChild(div)
			})
		}
		return str
	}
	return { yAxisWidth, updateYAxisWidth }
}

/** Subscribes to the container filter store and returns filtered DataPoints for container charts */
export function useContainerDataPoints(
	chartConfig: ChartConfig,
	// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
	dataFn: (key: string, data: Record<string, any>) => number | null
) {
	const filter = useStore($containerFilter)
	const { dataPoints, filteredKeys } = useMemo(() => {
		const filterTerms = filter
			? filter
					.toLowerCase()
					.split(" ")
					.filter((term) => term.length > 0)
			: []
		const filtered = new Set<string>()
		const points = Object.keys(chartConfig).map((key) => {
			const isFiltered = filterTerms.length > 0 && !filterTerms.some((term) => key.toLowerCase().includes(term))
			if (isFiltered) filtered.add(key)
			return {
				label: key,
				// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
				dataKey: (data: Record<string, any>) => dataFn(key, data),
				color: chartConfig[key].color ?? "",
				opacity: isFiltered ? 0.05 : 0.4,
				strokeOpacity: isFiltered ? 0.1 : 1,
				activeDot: !isFiltered,
				stackId: "a",
			}
		})
		return {
			// biome-ignore lint/suspicious/noExplicitAny: container data records have dynamic keys
			dataPoints: points as DataPoint<Record<string, any>>[],
			filteredKeys: filtered,
		}
	}, [chartConfig, filter])
	return { filter, dataPoints, filteredKeys }
}

// Assures consistent colors for network interfaces
export function useNetworkInterfaces(interfaces: SystemStats["ni"]) {
	const keys = Object.keys(interfaces ?? {})
	const sortedKeys = keys.sort((a, b) => (interfaces?.[b]?.[3] ?? 0) - (interfaces?.[a]?.[3] ?? 0))
	return {
		length: sortedKeys.length,
		data: (index = 3) => {
			return sortedKeys.map((key) => ({
				label: key,
				dataKey: ({ stats }: SystemStatsRecord) => stats?.ni?.[key]?.[index],
				color: `hsl(${220 + (((sortedKeys.indexOf(key) * 360) / sortedKeys.length) % 360)}, 70%, 50%)`,

				opacity: 0.3,
			}))
		},
	}
}
