import * as fs from "node:fs/promises";
import * as path from "node:path";
import { isEnoent, logger } from "@oh-my-pi/pi-utils";
import { getAgentDir } from "@oh-my-pi/pi-utils/dirs";

const SMITHERY_AUTH_FILENAME = "smithery.json";
const SMITHERY_URL = process.env.SMITHERY_URL || "https://smithery.ai";

type SmitheryCliAuthSession = {
	sessionId: string;
	authUrl: string;
};

type SmitheryCliPollResponse = {
	status: "pending" | "success" | "error";
	apiKey?: string;
	message?: string;
};

type SmitheryAuthPayload = {
	apiKey?: string;
};

function getSmitheryAuthPath(): string {
	return path.join(getAgentDir(), SMITHERY_AUTH_FILENAME);
}

function normalizeApiKey(value: string | undefined): string | undefined {
	if (!value) return undefined;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : undefined;
}

export function getSmitheryLoginUrl(): string {
	return SMITHERY_URL;
}

export async function createSmitheryCliAuthSession(): Promise<SmitheryCliAuthSession> {
	const response = await fetch(`${SMITHERY_URL}/api/auth/cli/session`, {
		method: "POST",
	});
	if (!response.ok) {
		throw new Error(`Failed to create Smithery auth session: ${response.status} ${response.statusText}`);
	}
	return (await response.json()) as SmitheryCliAuthSession;
}

export async function pollSmitheryCliAuthSession(
	sessionId: string,
	signal?: AbortSignal,
): Promise<SmitheryCliPollResponse> {
	const response = await fetch(`${SMITHERY_URL}/api/auth/cli/poll/${sessionId}`, {
		signal,
	});
	if (!response.ok) {
		if (response.status === 404 || response.status === 410) {
			throw new Error("Smithery login session expired. Please try again.");
		}
		throw new Error(`Smithery auth polling failed: ${response.status} ${response.statusText}`);
	}
	return (await response.json()) as SmitheryCliPollResponse;
}

export async function getSmitheryApiKey(): Promise<string | undefined> {
	const envKey = normalizeApiKey(process.env.SMITHERY_API_KEY);
	if (envKey) return envKey;

	const authPath = getSmitheryAuthPath();
	try {
		const payload = (await Bun.file(authPath).json()) as SmitheryAuthPayload;
		return normalizeApiKey(payload.apiKey);
	} catch (error) {
		if (isEnoent(error)) return undefined;
		logger.warn("Failed to read Smithery auth file, treating as missing", { path: authPath, error });
		return undefined;
	}
}

export async function saveSmitheryApiKey(apiKey: string): Promise<void> {
	const normalized = normalizeApiKey(apiKey);
	if (!normalized) {
		throw new Error("Smithery API key cannot be empty.");
	}

	const authPath = getSmitheryAuthPath();
	const payload: SmitheryAuthPayload = { apiKey: normalized };
	await Bun.write(authPath, `${JSON.stringify(payload, null, 2)}\n`);
	try {
		await fs.chmod(authPath, 0o600);
	} catch (error) {
		logger.warn("Could not set restrictive permissions on Smithery auth file", { path: authPath, error });
	}
}

export async function clearSmitheryApiKey(): Promise<boolean> {
	const authPath = getSmitheryAuthPath();
	try {
		await fs.rm(authPath);
		return true;
	} catch (error) {
		if (isEnoent(error)) return false;
		throw error;
	}
}