import type { SchemaResponse } from "./types";

const OPENVIP = "/openvip";
const API = "/api";

export async function fetchSchema(): Promise<SchemaResponse> {
	const r = await fetch(`${API}/settings/schema`);
	if (!r.ok) throw new Error(`Failed to load schema: ${r.status}`);
	return r.json();
}

export type PresetEntry = {
	default: unknown;
	values?: { value: string; label: string }[];
};

export type PresetsResponse = Record<string, PresetEntry>;

export async function fetchPresets(): Promise<PresetsResponse> {
	const r = await fetch(`${API}/settings/presets`);
	if (!r.ok) throw new Error(`Failed to load presets: ${r.status}`);
	return r.json();
}

export async function saveSetting(
	key: string,
	value: unknown
): Promise<{ status: string; key: string; value: unknown }> {
	const r = await fetch(`${API}/settings`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ key, value: String(value) })
	});
	if (!r.ok) {
		const data = await r.json();
		throw new Error(data.detail || `Save failed: ${r.status}`);
	}
	return r.json();
}

export async function fetchTomlSection(section: string): Promise<string> {
	const r = await fetch(`${API}/settings/toml-section/${section}`);
	if (!r.ok) throw new Error(`Failed to load section: ${r.status}`);
	const data = await r.json();
	return data.content as string;
}

export async function saveTomlSection(
	section: string,
	content: string
): Promise<void> {
	const r = await fetch(`${API}/settings/toml-section/${section}`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ content })
	});
	if (!r.ok) {
		const data = await r.json().catch(() => ({}));
		throw new Error(data.detail || `Save failed: ${r.status}`);
	}
}

export type Shortcut = { keys: string; command: string };

export async function fetchShortcuts(): Promise<Shortcut[]> {
	const r = await fetch(`${API}/settings/shortcuts`);
	if (!r.ok) throw new Error(`Failed to load shortcuts: ${r.status}`);
	const data = await r.json();
	return data.shortcuts as Shortcut[];
}

export async function saveShortcuts(shortcuts: Shortcut[]): Promise<void> {
	const r = await fetch(`${API}/settings/shortcuts`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ shortcuts }),
	});
	if (!r.ok) {
		const data = await r.json().catch(() => ({}));
		throw new Error(data.detail || `Save failed: ${r.status}`);
	}
}

export async function pingEngine(): Promise<boolean> {
	try {
		const r = await fetch(`${OPENVIP}/control`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ command: "ping" })
		});
		return r.ok;
	} catch {
		return false;
	}
}

export async function captureHotkey(signal?: AbortSignal): Promise<string | null> {
	try {
		const r = await fetch(`${OPENVIP}/control`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ command: "hotkey.capture", timeout: 10 }),
			signal,
		});
		if (!r.ok) return null;
		const data = await r.json();
		return data.key as string | null;
	} catch {
		return null;
	}
}

// ----- Audio Devices API -----

export type AudioDeviceInfo = {
	index: number;
	name: string;
	channels: number;
	sample_rate: number;
};

export type AudioDevicesResponse = {
	input: AudioDeviceInfo[];
	output: AudioDeviceInfo[];
	default_input: AudioDeviceInfo | null;
	default_output: AudioDeviceInfo | null;
};

export async function fetchAudioDevices(): Promise<AudioDevicesResponse> {
	const r = await fetch(`${API}/audio/devices`);
	if (!r.ok) throw new Error(`Failed to load audio devices: ${r.status}`);
	return r.json();
}

export async function setAudioDevice(type: "input" | "output", device: string): Promise<void> {
	const r = await fetch(`${API}/audio/device`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ type, device }),
	});
	if (!r.ok) {
		const data = await r.json().catch(() => ({}));
		throw new Error(data.detail || `Failed to set audio device: ${r.status}`);
	}
}

// ----- Models API -----

export type ModelInfo = {
	id: string;
	type: "stt" | "tts";
	description: string;
	size_gb: number;
	cached: boolean;
	cache_size_bytes: number;
	configured: string;
	downloading: boolean;
	download_fraction: number | null;
	downloaded_bytes: number;
	total_bytes: number;
};

export async function fetchModels(): Promise<ModelInfo[]> {
	const r = await fetch(`${API}/models`);
	if (!r.ok) throw new Error(`Failed to load models: ${r.status}`);
	const data = await r.json();
	return data.models as ModelInfo[];
}

export async function pullModel(modelId: string): Promise<string> {
	const r = await fetch(`${API}/models/${modelId}/pull`, { method: "POST" });
	if (!r.ok) throw new Error(`Pull failed: ${r.status}`);
	const data = await r.json();
	return data.status as string;
}

export function createPullProgressSource(): EventSource {
	return new EventSource(`${API}/models/pull-progress`);
}

// ----- Status / Dashboard API -----

export type EngineInfo = {
	name: string;
	available: boolean;
	description: string;
	platform_ok: boolean;
	install_hint: string;
	configured: boolean;
	venv_installed: boolean;
	needs_venv: boolean;
};

export type StatusResponse = {
	openvip: string;
	stt: { enabled: boolean; active: boolean };
	tts: { enabled: boolean };
	connected_agents: string[];
	platform: {
		name: string;
		version: string;
		mode: string;
		state: string;
		uptime_seconds: number;
		stt: { model_name: string; device: string; last_text: string };
		tts: { engine: string; language: string; available: boolean; error: string | null };
		output: { mode: string; current_agent: string; available_agents: string[] };
		hotkey: { key: string; bound: boolean; status?: string };
		permissions: Record<string, boolean>;
		engines: {
			tts: EngineInfo[];
			stt: EngineInfo[];
		};
		loading: { active: boolean; models: { name: string; status: string }[] };
		stats: { transcriptions: number; words: number; chars: number; audio_seconds: number; phrase: string };
		audio_in_use?: { input: string | null; output: string | null };
		audio_devices_available?: {
			input: AudioDeviceInfo[];
			output: AudioDeviceInfo[];
			default_input: AudioDeviceInfo | null;
			default_output: AudioDeviceInfo | null;
		};
	};
};

export async function fetchStatus(): Promise<StatusResponse> {
	const r = await fetch(`${OPENVIP}/status`);
	if (!r.ok) throw new Error(`Failed to load status: ${r.status}`);
	return r.json();
}

export async function setCurrentAgent(agent: string): Promise<void> {
	try {
		await fetch(`${OPENVIP}/control`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ command: `output.set_agent:${agent}` }),
		});
	} catch {
		// Engine might be briefly unresponsive
	}
}

export async function setOutputMode(mode: "keyboard" | "agents"): Promise<void> {
	try {
		await fetch(`${OPENVIP}/control`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ command: `output.set_mode:${mode}` }),
		});
	} catch {
		// Engine might be briefly unresponsive
	}
}

export async function restartEngine(): Promise<void> {
	try {
		await fetch(`${OPENVIP}/control`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ command: "engine.restart" })
		});
	} catch {
		// Expected: engine shuts down mid-restart, connection drops
	}
}

// ----- TTS Venv Install/Uninstall API -----

export async function installTtsEngine(engine: string): Promise<string> {
	const r = await fetch(`${API}/tts-engines/${engine}/install`, { method: "POST" });
	if (!r.ok) throw new Error(`Install failed: ${r.status}`);
	const data = await r.json();
	return data.status as string;
}

export async function uninstallTtsEngine(engine: string): Promise<void> {
	const r = await fetch(`${API}/tts-engines/${engine}/install`, { method: "DELETE" });
	if (!r.ok) throw new Error(`Uninstall failed: ${r.status}`);
}

// ----- Capabilities API (unified models + engines) -----

export type CapabilityInfo = {
	id: string;
	type: "stt" | "tts";
	description: string;
	size_gb: number;
	platform_ok: boolean;
	ready: boolean;
	venv_installed: boolean | null;
	model_cached: boolean | null;
	configured: boolean;
	builtin: boolean;
	downloading: boolean;
	download_fraction: number | null;
};

export async function fetchCapabilities(): Promise<CapabilityInfo[]> {
	const r = await fetch(`${API}/capabilities`);
	if (!r.ok) throw new Error(`Failed to load capabilities: ${r.status}`);
	const data = await r.json();
	return data.capabilities as CapabilityInfo[];
}

export async function installCapability(id: string): Promise<string> {
	const r = await fetch(`${API}/capabilities/${id}/install`, { method: "POST" });
	if (!r.ok) throw new Error(`Install failed: ${r.status}`);
	const data = await r.json();
	return data.status as string;
}

export async function uninstallCapability(id: string): Promise<void> {
	const r = await fetch(`${API}/capabilities/${id}/install`, { method: "DELETE" });
	if (!r.ok) throw new Error(`Uninstall failed: ${r.status}`);
}

export async function selectCapability(id: string): Promise<void> {
	const r = await fetch(`${API}/capabilities/${id}/select`, { method: "POST" });
	if (!r.ok) {
		const data = await r.json().catch(() => ({}));
		throw new Error(data.detail || `Select failed: ${r.status}`);
	}
}

export async function getSystemInfo(): Promise<{ platform: string; launch_at_login: boolean | null }> {
	const r = await fetch(`${API}/system`);
	if (!r.ok) throw new Error(`Failed to get system info: ${r.status}`);
	return r.json();
}

export async function setLaunchAtLogin(enabled: boolean): Promise<void> {
	const r = await fetch(`${API}/system`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ launch_at_login: enabled }),
	});
	if (!r.ok) throw new Error(`Failed to set launch at login: ${r.status}`);
}

export async function getHotkeyStatus(): Promise<{ status: string }> {
	const r = await fetch(`${API}/hotkey/status`);
	if (!r.ok) throw new Error(`Failed to get hotkey status: ${r.status}`);
	return r.json();
}

export async function fixHotkey(): Promise<void> {
	await fetch(`${API}/hotkey/fix`, { method: "POST" });
}

export type PermissionDoctorStatus = {
	platform: string;
	status: string;
	accessibility?: boolean;
	microphone?: boolean;
	input_monitoring?: boolean;
	hotkey_status?: string;
	capture_healthy?: boolean;
	active_provider?: string;
	diagnosis?: {
		code: string;
		summary: string;
		steps: string[];
		recommended_target?: "input_monitoring" | "accessibility" | "microphone" | null;
	};
};

export async function getPermissionDoctorStatus(): Promise<PermissionDoctorStatus> {
	const r = await fetch(`${API}/permissions/doctor`);
	if (!r.ok) throw new Error(`Failed to get doctor status: ${r.status}`);
	return r.json();
}

export async function openPermissionSetting(target: "input_monitoring" | "accessibility" | "microphone"): Promise<void> {
	const r = await fetch(`${API}/permissions/doctor/open`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ target }),
	});
	if (!r.ok) throw new Error(`Failed to open settings: ${r.status}`);
}

export type PermissionProbeResult = {
	ok: boolean;
	message: string;
	delivered_count: number;
	active_provider: string;
	capture_healthy: boolean;
	hotkey_status: string;
	diagnosis?: {
		code: string;
		summary: string;
		steps: string[];
		recommended_target?: "input_monitoring" | "accessibility" | "microphone" | null;
	};
};

export async function probePermissionDoctor(timeout = 8): Promise<PermissionProbeResult> {
	const r = await fetch(`${API}/permissions/doctor/probe`, {
		method: "POST",
		headers: { "Content-Type": "application/json" },
		body: JSON.stringify({ timeout }),
	});
	if (!r.ok) throw new Error(`Probe failed: ${r.status}`);
	return r.json();
}
