import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import type { Credentials } from "./types";

const CONFIG_DIR = path.join(os.homedir(), ".config", "sequoia");
const CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials.json");

// Stored credentials keyed by identifier
type CredentialsStore = Record<string, Credentials>;

async function fileExists(filePath: string): Promise<boolean> {
	try {
		await fs.access(filePath);
		return true;
	} catch {
		return false;
	}
}

/**
 * Load all stored credentials
 */
async function loadCredentialsStore(): Promise<CredentialsStore> {
	if (!(await fileExists(CREDENTIALS_FILE))) {
		return {};
	}

	try {
		const content = await fs.readFile(CREDENTIALS_FILE, "utf-8");
		const parsed = JSON.parse(content);

		// Handle legacy single-credential format (migrate on read)
		if (parsed.identifier && parsed.password) {
			const legacy = parsed as Credentials;
			return { [legacy.identifier]: legacy };
		}

		return parsed as CredentialsStore;
	} catch {
		return {};
	}
}

/**
 * Save the entire credentials store
 */
async function saveCredentialsStore(store: CredentialsStore): Promise<void> {
	await fs.mkdir(CONFIG_DIR, { recursive: true });
	await fs.writeFile(CREDENTIALS_FILE, JSON.stringify(store, null, 2));
	await fs.chmod(CREDENTIALS_FILE, 0o600);
}

/**
 * Load credentials for a specific identity or resolve which to use.
 *
 * Priority:
 * 1. Full env vars (ATP_IDENTIFIER + ATP_APP_PASSWORD)
 * 2. SEQUOIA_PROFILE env var - selects from stored credentials
 * 3. projectIdentity parameter (from sequoia.json)
 * 4. If only one identity stored, use it
 * 5. Return null (caller should prompt user)
 */
export async function loadCredentials(
	projectIdentity?: string,
): Promise<Credentials | null> {
	// 1. Check environment variables first (full override)
	const envIdentifier = process.env.ATP_IDENTIFIER;
	const envPassword = process.env.ATP_APP_PASSWORD;
	const envPdsUrl = process.env.PDS_URL;

	if (envIdentifier && envPassword) {
		return {
			identifier: envIdentifier,
			password: envPassword,
			pdsUrl: envPdsUrl || "https://bsky.social",
		};
	}

	const store = await loadCredentialsStore();
	const identifiers = Object.keys(store);

	if (identifiers.length === 0) {
		return null;
	}

	// 2. SEQUOIA_PROFILE env var
	const profileEnv = process.env.SEQUOIA_PROFILE;
	if (profileEnv && store[profileEnv]) {
		return store[profileEnv];
	}

	// 3. Project-specific identity (from sequoia.json)
	if (projectIdentity && store[projectIdentity]) {
		return store[projectIdentity];
	}

	// 4. If only one identity, use it
	if (identifiers.length === 1 && identifiers[0]) {
		return store[identifiers[0]] ?? null;
	}

	// Multiple identities exist but none selected
	return null;
}

/**
 * Get a specific identity by identifier
 */
export async function getCredentials(
	identifier: string,
): Promise<Credentials | null> {
	const store = await loadCredentialsStore();
	return store[identifier] || null;
}

/**
 * List all stored identities
 */
export async function listCredentials(): Promise<string[]> {
	const store = await loadCredentialsStore();
	return Object.keys(store);
}

/**
 * Save credentials for an identity (adds or updates)
 */
export async function saveCredentials(credentials: Credentials): Promise<void> {
	const store = await loadCredentialsStore();
	store[credentials.identifier] = credentials;
	await saveCredentialsStore(store);
}

/**
 * Delete credentials for a specific identity
 */
export async function deleteCredentials(identifier?: string): Promise<boolean> {
	const store = await loadCredentialsStore();
	const identifiers = Object.keys(store);

	if (identifiers.length === 0) {
		return false;
	}

	// If identifier specified, delete just that one
	if (identifier) {
		if (!store[identifier]) {
			return false;
		}
		delete store[identifier];
		await saveCredentialsStore(store);
		return true;
	}

	// If only one identity, delete it (backwards compat behavior)
	if (identifiers.length === 1 && identifiers[0]) {
		delete store[identifiers[0]];
		await saveCredentialsStore(store);
		return true;
	}

	// Multiple identities but none specified
	return false;
}

export function getCredentialsPath(): string {
	return CREDENTIALS_FILE;
}
