import { PUBLIC_EMAIL_API_URL, PUBLIC_EMAIL_API_KEY } from '$env/static/public';

// Types matching the emailer microservice API

export interface EmailError {
	error: string;
	message: string;
}

export interface EmailAttachment {
	filename: string;
	content: string; // base64 encoded
	contentType: string;
}

export interface SendEmailInput {
	to: string[];
	cc?: string[];
	bcc?: string[];
	subject: string;
	body: string;
	contentType?: 'text/html' | 'text/plain';
	fromName?: string;
	attachments?: EmailAttachment[];
}

export interface EmailHeader {
	name: string;
	value: string;
}

export interface EmailBody {
	attachmentId?: string;
	size?: number;
	data?: string; // base64 encoded
}

export interface EmailPayload {
	partId?: string;
	mimeType?: string;
	filename?: string;
	headers?: EmailHeader[];
	body?: EmailBody;
	parts?: EmailPayload[];
}

export interface EmailMessage {
	id: string;
	threadId: string;
	labelIds?: string[];
	snippet?: string;
	payload?: EmailPayload;
	sizeEstimate?: number;
	historyId?: string;
	internalDate?: string;
}

export interface EmailMessageRef {
	id: string;
	threadId: string;
}

export interface ListEmailsResponse {
	messages?: EmailMessageRef[];
	nextPageToken?: string;
	resultSizeEstimate?: number;
}

export interface ListEmailsParams {
	q?: string; // Gmail search query
	maxResults?: number;
	pageToken?: string;
	labelIds?: string[];
	includeSpamTrash?: boolean;
}

export interface EmailTemplate {
	templateId: string;
	subjectTemplate: string;
	bodyTemplate: string;
	variables: Record<string, string>;
}

export interface SendTemplateInput {
	to: string[];
	cc?: string[];
	bcc?: string[];
	templateId: string;
	variables: Record<string, string>;
}

class EmailService {
	private readonly baseUrl: string;
	private readonly apiKey: string;

	constructor() {
		this.baseUrl = PUBLIC_EMAIL_API_URL;
		this.apiKey = PUBLIC_EMAIL_API_KEY;
	}

	private async request<T>(
		endpoint: string,
		options: RequestInit = {},
		impersonateUser?: string
	): Promise<{ data?: T; error?: EmailError }> {
		const url = `${this.baseUrl}${endpoint}`;

		const headers: HeadersInit = {
			'X-API-Key': this.apiKey,
			'Content-Type': 'application/json',
			...options.headers
		};

		if (impersonateUser) {
			(headers as Record<string, string>)['X-Impersonate-User'] = impersonateUser;
		}

		try {
			const response = await fetch(url, {
				...options,
				headers
			});

			// Handle 204 No Content (for delete operations)
			if (response.status === 204) {
				return { data: undefined };
			}

			const data = await response.json();

			if (!response.ok) {
				return { error: data as EmailError };
			}

			return { data: data as T };
		} catch (err) {
			console.error('Email API error:', err);
			return {
				error: {
					error: 'NetworkError',
					message: err instanceof Error ? err.message : 'Unknown network error'
				}
			};
		}
	}

	/**
	 * Send an email
	 */
	async sendEmail(
		input: SendEmailInput,
		impersonateUser?: string
	): Promise<{ data?: EmailMessage; error?: EmailError }> {
		return this.request<EmailMessage>(
			'/emails',
			{
				method: 'POST',
				body: JSON.stringify(input)
			},
			impersonateUser
		);
	}

	/**
	 * List emails with optional filters
	 */
	async listEmails(
		params: ListEmailsParams = {},
		impersonateUser?: string
	): Promise<{ data?: ListEmailsResponse; error?: EmailError }> {
		const searchParams = new URLSearchParams();

		if (params.q) searchParams.set('q', params.q);
		if (params.maxResults) searchParams.set('maxResults', params.maxResults.toString());
		if (params.pageToken) searchParams.set('pageToken', params.pageToken);
		if (params.labelIds) {
			params.labelIds.forEach((id) => searchParams.append('labelIds', id));
		}
		if (params.includeSpamTrash !== undefined) {
			searchParams.set('includeSpamTrash', params.includeSpamTrash.toString());
		}

		const queryString = searchParams.toString();
		const endpoint = `/emails${queryString ? `?${queryString}` : ''}`;

		return this.request<ListEmailsResponse>(endpoint, {}, impersonateUser);
	}

	/**
	 * Get a single email by ID
	 */
	async getEmail(
		emailId: string,
		impersonateUser?: string
	): Promise<{ data?: EmailMessage; error?: EmailError }> {
		return this.request<EmailMessage>(`/emails/${emailId}`, {}, impersonateUser);
	}

	/**
	 * Delete an email
	 */
	async deleteEmail(emailId: string, impersonateUser?: string): Promise<{ error?: EmailError }> {
		return this.request<void>(
			`/emails/${emailId}`,
			{
				method: 'DELETE'
			},
			impersonateUser
		);
	}

	/**
	 * Mark an email as read
	 */
	async markAsRead(
		emailId: string,
		impersonateUser?: string
	): Promise<{ data?: EmailMessage; error?: EmailError }> {
		return this.request<EmailMessage>(
			`/emails/${emailId}/read`,
			{
				method: 'POST'
			},
			impersonateUser
		);
	}

	/**
	 * Mark an email as unread
	 */
	async markAsUnread(
		emailId: string,
		impersonateUser?: string
	): Promise<{ data?: EmailMessage; error?: EmailError }> {
		return this.request<EmailMessage>(
			`/emails/${emailId}/unread`,
			{
				method: 'POST'
			},
			impersonateUser
		);
	}

	/**
	 * List available email templates
	 */
	async listTemplates(): Promise<{ data?: string[]; error?: EmailError }> {
		return this.request<string[]>('/templates');
	}

	/**
	 * Get a template by ID
	 */
	async getTemplate(templateId: string): Promise<{ data?: EmailTemplate; error?: EmailError }> {
		return this.request<EmailTemplate>(`/templates/${templateId}`);
	}

	/**
	 * Send an email using a template
	 */
	async sendTemplate(
		input: SendTemplateInput,
		impersonateUser?: string
	): Promise<{ data?: EmailMessage; error?: EmailError }> {
		return this.request<EmailMessage>(
			'/templates/send',
			{
				method: 'POST',
				body: JSON.stringify(input)
			},
			impersonateUser
		);
	}

	/**
	 * Health check for the email service
	 */
	async healthCheck(): Promise<{ data?: { status: string; message: string }; error?: EmailError }> {
		// Health endpoint is at root, not under /api/v1
		const url = this.baseUrl.replace('/api/v1', '') + '/health';

		try {
			const response = await fetch(url);
			const data = await response.json();

			if (!response.ok) {
				return { error: data as EmailError };
			}

			return { data: data as { status: string; message: string } };
		} catch (err) {
			console.error('Email API health check error:', err);
			return {
				error: {
					error: 'NetworkError',
					message: err instanceof Error ? err.message : 'Unknown network error'
				}
			};
		}
	}
}

// Export singleton instance
export const emailService = new EmailService();

// Export class for testing or custom instances
export { EmailService };
