import type { ComponentType } from "react";
import { AlertmanagerAlertsWidget } from "../widgets/AlertmanagerAlertsWidget";
import { BackupsWidget } from "../widgets/BackupsWidget";
import { PrometheusChartWidget } from "../widgets/PrometheusChartWidget";
import { PrometheusGaugeWidget } from "../widgets/PrometheusGaugeWidget";
import { PrometheusMeanWidget } from "../widgets/PrometheusMeanWidget";
import { JellyfinWidget } from "../widgets/JellyfinWidget";
import { JellyfinNowPlayingWidget } from "../widgets/JellyfinNowPlayingWidget";
import { PrometheusMetricWidget } from "../widgets/PrometheusMetricWidget";
import { QbittorrentActiveTorrentsWidget } from "../widgets/QbittorrentActiveTorrentsWidget";
import { QbittorrentSpeedWidget } from "../widgets/QbittorrentSpeedWidget";
import { QbittorrentTotalsWidget } from "../widgets/QbittorrentTotalsWidget";
import { SshTaskWidget } from "../widgets/SshTaskWidget";
import { StaticWidget } from "../widgets/StaticWidget";
import type {
	ServiceInstance,
	ServiceTypeInfo,
	WidgetInstance,
} from "../types";

/**
 * Closed frontend registry mirroring the backend service definitions.
 *
 * Each service type maps its widget kinds to a presentational component and a
 * refresh interval. Built-in (service-less) kinds are listed separately.
 */

export interface WidgetComponentProps {
	widget: WidgetInstance;
	refreshIntervalMs: number;
	description?: string;
}

export interface ServiceWidgetBinding {
	kind: string;
	name: string;
	description: string;
	refreshIntervalMs: number;
	defaultConfig: Record<string, unknown>;
	configSchema: Record<string, unknown>;
	component: ComponentType<WidgetComponentProps>;
}

export interface ServiceBinding {
	serviceType: string;
	name: string;
	description: string;
	widgets: ServiceWidgetBinding[];
}

export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
	alertmanager: {
		serviceType: "alertmanager",
		name: "Alertmanager",
		description: "Alertmanager alerts and status.",
		widgets: [
			{
				kind: "active_alerts",
				name: "Active alerts",
				description: "Firing alerts summary from Alertmanager.",
				refreshIntervalMs: 30_000,
				defaultConfig: {},
				configSchema: {
					type: "object",
					properties: {
						severity_filter: { type: "string" },
					},
					required: [],
				},
				component: AlertmanagerAlertsWidget,
			},
		],
	},
	prometheus: {
		serviceType: "prometheus",
		name: "Prometheus",
		description: "Metrics storage and PromQL queries.",
		widgets: [
			{
				kind: "metric",
				name: "Metric",
				description: "Instant query result rendered as a metric.",
				refreshIntervalMs: 30_000,
				defaultConfig: { promql: "" },
				configSchema: {
					type: "object",
					properties: { promql: { type: "string" } },
					required: ["promql"],
				},
				component: PrometheusMetricWidget,
			},
			{
				kind: "chart",
				name: "Chart",
				description: "Multi-series line chart from a PromQL range query.",
				refreshIntervalMs: 60_000,
				defaultConfig: { promql: "", window: "1h" },
				configSchema: {
					type: "object",
					properties: {
						promql: {
							type: "string",
							description: "PromQL range query expression",
						},
						window: {
							type: "string",
							description: "Time window preset (1h, 6h, 24h, 7d)",
						},
					},
					required: ["promql"],
				},
				component: PrometheusChartWidget,
			},
			{
				kind: "gauge",
				name: "Gauge",
				description:
					"Instant query rendered as a gauge with optional threshold bands.",
				refreshIntervalMs: 30_000,
				defaultConfig: { promql: "" },
				configSchema: {
					type: "object",
					properties: {
						promql: {
							type: "string",
							description: "PromQL instant query (must return a single scalar)",
						},
						warn_at: { type: "number", description: "Warning threshold" },
						crit_at: { type: "number", description: "Critical threshold" },
						min: { type: "number" },
						max: { type: "number" },
						unit: { type: "string" },
					},
					required: ["promql"],
				},
				component: PrometheusGaugeWidget,
			},
			{
				kind: "mean",
				name: "Mean",
				description: "Average value of a PromQL query over a time window.",
				refreshIntervalMs: 60_000,
				defaultConfig: { promql: "", window: "1h" },
				configSchema: {
					type: "object",
					properties: {
						promql: {
							type: "string",
							description: "PromQL range query (must return a single series)",
						},
						window: {
							type: "string",
							description: "Time window preset (1h, 6h, 24h, 7d)",
						},
						unit: { type: "string" },
					},
					required: ["promql"],
				},
				component: PrometheusMeanWidget,
			},
		],
	},
	qbittorrent: {
		serviceType: "qbittorrent",
		name: "qBittorrent",
		description: "Torrent client activity, speeds, and item counts.",
		widgets: [
			{
				kind: "totals",
				name: "Totals",
				description: "Count of all listed torrents, broken down by state.",
				refreshIntervalMs: 30_000,
				defaultConfig: {},
				configSchema: { type: "object", properties: {}, required: [] },
				component: QbittorrentTotalsWidget,
			},
			{
				kind: "active",
				name: "Active torrents",
				description: "Torrents currently downloading or uploading.",
				refreshIntervalMs: 15_000,
				defaultConfig: {},
				configSchema: { type: "object", properties: {}, required: [] },
				component: QbittorrentActiveTorrentsWidget,
			},
			{
				kind: "speed",
				name: "Speed chart",
				description: "Live download/upload speed over a short window.",
				refreshIntervalMs: 5_000,
				defaultConfig: {},
				configSchema: { type: "object", properties: {}, required: [] },
				component: QbittorrentSpeedWidget,
			},
		],
	},
	jellyfin: {
		serviceType: "jellyfin",
		name: "Jellyfin",
		description: "Media server with live session activity.",
		widgets: [
			{
				kind: "activity",
				name: "Activity",
				description: "Live sessions and idle users.",
				refreshIntervalMs: 30_000,
				defaultConfig: {},
				configSchema: { type: "object", properties: {}, required: [] },
				component: JellyfinWidget,
			},
			{
				kind: "now_playing",
				name: "Now Playing",
				description: "Only sessions actively playing media.",
				refreshIntervalMs: 30_000,
				defaultConfig: {},
				configSchema: { type: "object", properties: {}, required: [] },
				component: JellyfinNowPlayingWidget,
			},
		],
	},
	nextcloud: {
		serviceType: "nextcloud",
		name: "Nextcloud",
		description: "Self-hosted files and collaboration.",
		widgets: [],
	},
	ssh_tasks: {
		serviceType: "ssh_tasks",
		name: "SSH task runner",
		description: "Run reusable saved tasks over SSH and keep run history.",
		widgets: [
			{
				kind: "task_output",
				name: "Task output",
				description: "Output of a saved task run.",
				refreshIntervalMs: 0,
				defaultConfig: { task_id: "" },
				configSchema: {
					type: "object",
					properties: { task_id: { type: "string" } },
					required: ["task_id"],
				},
				component: SshTaskWidget,
			},
		],
	},
};

export const BUILTIN_WIDGETS: Record<string, ServiceWidgetBinding> = {
	backups: {
		kind: "backups",
		name: "Backups",
		description: "Backup job summary and active alerts.",
		refreshIntervalMs: 60_000,
		defaultConfig: {},
		configSchema: { type: "object", properties: {}, required: [] },
		component: BackupsWidget,
	},
	static: {
		kind: "static",
		name: "Static text",
		description: "Plain text or markdown note.",
		refreshIntervalMs: 0,
		defaultConfig: { text: "" },
		configSchema: {
			type: "object",
			properties: { text: { type: "string" } },
			required: ["text"],
		},
		component: StaticWidget,
	},
};

export function getServiceBinding(
	serviceType: string,
): ServiceBinding | undefined {
	return SERVICE_REGISTRY[serviceType];
}

export function getBuiltinBinding(
	kind: string,
): ServiceWidgetBinding | undefined {
	return BUILTIN_WIDGETS[kind];
}

export interface ResolvedWidget {
	component: ComponentType<WidgetComponentProps>;
	description: string;
	refreshIntervalMs: number;
}

/**
 * Resolve a widget instance to its component + metadata.
 *
 * Service-bound widgets are resolved via the parent service's type (looked up
 * from the services list); built-in widgets are resolved directly.
 */
export function resolveWidget(
	widget: WidgetInstance,
	services: ServiceInstance[],
): ResolvedWidget | undefined {
	if (widget.service_id) {
		const service = services.find((s) => s.id === widget.service_id);
		if (!service) return undefined;
		const binding = getServiceBinding(service.service_type);
		const widgetBinding = binding?.widgets.find(
			(w) => w.kind === widget.widget_kind,
		);
		if (!widgetBinding) return undefined;
		return {
			component: widgetBinding.component,
			description: widgetBinding.description,
			refreshIntervalMs: widgetBinding.refreshIntervalMs,
		};
	}
	const builtin = getBuiltinBinding(widget.widget_kind);
	if (!builtin) return undefined;
	return {
		component: builtin.component,
		description: builtin.description,
		refreshIntervalMs: builtin.refreshIntervalMs,
	};
}

/** Merge backend type metadata (config_schema, secret_fields) onto bindings. */
export function enrichServiceTypes(
	types: ServiceTypeInfo[],
): ServiceTypeInfo[] {
	return types;
}
