/**
 * Poste.io Mail Server API Client
 * Documentation: https://mail.monacousa.org/admin/api/doc
 */

export interface PosteConfig {
	host: string;
	adminEmail: string;
	adminPassword: string;
}

export interface Mailbox {
	address: string;
	name: string;
	disabled: boolean;
	super_admin: boolean;
	created?: string;
	storage_limit?: number;
	storage_usage?: number;
}

export interface MailboxQuota {
	storageLimit: number;
	storageUsed: number;
}

interface ApiResponse<T> {
	success: boolean;
	data?: T;
	error?: string;
}

/**
 * Make an authenticated request to the Poste API
 */
async function makeRequest<T>(
	config: PosteConfig,
	method: string,
	endpoint: string,
	body?: Record<string, unknown>
): Promise<ApiResponse<T>> {
	const baseUrl = `https://${config.host}/admin/api/v1`;
	const auth = Buffer.from(`${config.adminEmail}:${config.adminPassword}`).toString('base64');

	try {
		const response = await fetch(`${baseUrl}${endpoint}`, {
			method,
			headers: {
				'Authorization': `Basic ${auth}`,
				'Content-Type': 'application/json',
				'Accept': 'application/json'
			},
			body: body ? JSON.stringify(body) : undefined
		});

		if (!response.ok) {
			const errorText = await response.text();
			let errorMessage = `HTTP ${response.status}`;
			try {
				const errorJson = JSON.parse(errorText);
				errorMessage = errorJson.message || errorJson.error || errorMessage;
			} catch {
				errorMessage = errorText || errorMessage;
			}
			return { success: false, error: errorMessage };
		}

		// Handle empty responses (e.g., DELETE)
		const text = await response.text();
		if (!text) {
			return { success: true };
		}

		const data = JSON.parse(text) as T;
		return { success: true, data };
	} catch (error) {
		const message = error instanceof Error ? error.message : 'Unknown error';
		return { success: false, error: message };
	}
}

/**
 * Test connection to the Poste API
 */
export async function testConnection(config: PosteConfig): Promise<{ success: boolean; error?: string }> {
	const result = await makeRequest<{ results: unknown[] }>(config, 'GET', '/domains');
	if (!result.success) {
		return { success: false, error: result.error };
	}
	return { success: true };
}

/**
 * List all mailboxes
 */
export async function listMailboxes(
	config: PosteConfig,
	options?: { query?: string; page?: number; limit?: number }
): Promise<{ success: boolean; mailboxes?: Mailbox[]; total?: number; error?: string }> {
	let endpoint = '/boxes';
	const params = new URLSearchParams();

	if (options?.query) params.set('query', options.query);
	if (options?.page) params.set('page', options.page.toString());
	if (options?.limit) params.set('paging', options.limit.toString());

	const queryString = params.toString();
	if (queryString) endpoint += `?${queryString}`;

	const result = await makeRequest<{ results: Mailbox[]; results_count: number }>(
		config,
		'GET',
		endpoint
	);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return {
		success: true,
		mailboxes: result.data?.results || [],
		total: result.data?.results_count || 0
	};
}

/**
 * Get a single mailbox
 */
export async function getMailbox(
	config: PosteConfig,
	email: string
): Promise<{ success: boolean; mailbox?: Mailbox; error?: string }> {
	const result = await makeRequest<Mailbox>(config, 'GET', `/boxes/${encodeURIComponent(email)}`);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return { success: true, mailbox: result.data };
}

/**
 * Create a new mailbox
 */
export async function createMailbox(
	config: PosteConfig,
	options: {
		email: string;
		name: string;
		password: string;
		disabled?: boolean;
		superAdmin?: boolean;
	}
): Promise<{ success: boolean; error?: string }> {
	const result = await makeRequest<Mailbox>(config, 'POST', '/boxes', {
		email: options.email,
		name: options.name,
		passwordPlaintext: options.password,
		disabled: options.disabled ?? false,
		superAdmin: options.superAdmin ?? false
	});

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return { success: true };
}

/**
 * Update a mailbox
 */
export async function updateMailbox(
	config: PosteConfig,
	email: string,
	updates: {
		name?: string;
		password?: string;
		disabled?: boolean;
		superAdmin?: boolean;
	}
): Promise<{ success: boolean; error?: string }> {
	const body: Record<string, unknown> = {};

	if (updates.name !== undefined) body.name = updates.name;
	if (updates.password !== undefined) body.passwordPlaintext = updates.password;
	if (updates.disabled !== undefined) body.disabled = updates.disabled;
	if (updates.superAdmin !== undefined) body.superAdmin = updates.superAdmin;

	const result = await makeRequest<Mailbox>(
		config,
		'PATCH',
		`/boxes/${encodeURIComponent(email)}`,
		body
	);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return { success: true };
}

/**
 * Delete a mailbox
 */
export async function deleteMailbox(
	config: PosteConfig,
	email: string
): Promise<{ success: boolean; error?: string }> {
	const result = await makeRequest<void>(
		config,
		'DELETE',
		`/boxes/${encodeURIComponent(email)}`
	);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return { success: true };
}

/**
 * Get mailbox storage quota
 */
export async function getMailboxQuota(
	config: PosteConfig,
	email: string
): Promise<{ success: boolean; quota?: MailboxQuota; error?: string }> {
	const result = await makeRequest<{ storageLimit: number; storageUsed: number }>(
		config,
		'GET',
		`/boxes/${encodeURIComponent(email)}/quota`
	);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return {
		success: true,
		quota: {
			storageLimit: result.data?.storageLimit || 0,
			storageUsed: result.data?.storageUsed || 0
		}
	};
}

/**
 * Set mailbox storage quota
 */
export async function setMailboxQuota(
	config: PosteConfig,
	email: string,
	storageLimitMB: number
): Promise<{ success: boolean; error?: string }> {
	const result = await makeRequest<void>(
		config,
		'PATCH',
		`/boxes/${encodeURIComponent(email)}/quota`,
		{ storageLimit: storageLimitMB }
	);

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return { success: true };
}

/**
 * List all domains
 */
export async function listDomains(
	config: PosteConfig
): Promise<{ success: boolean; domains?: string[]; error?: string }> {
	const result = await makeRequest<{ results: { name: string }[] }>(config, 'GET', '/domains');

	if (!result.success) {
		return { success: false, error: result.error };
	}

	return {
		success: true,
		domains: result.data?.results?.map(d => d.name) || []
	};
}

/**
 * Generate a random password
 */
export function generatePassword(length = 16): string {
	const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';
	let password = '';
	const randomValues = new Uint32Array(length);
	crypto.getRandomValues(randomValues);
	for (let i = 0; i < length; i++) {
		password += chars[randomValues[i] % chars.length];
	}
	return password;
}
