import { fail } from '@sveltejs/kit';
import type { Actions, PageServerLoad } from './$types';
import { testSmtpConnection, sendTemplatedEmail } from '$lib/server/email';
import { testS3Connection, clearS3ClientCache } from '$lib/server/storage';
import { supabaseAdmin } from '$lib/server/supabase';
import * as poste from '$lib/server/poste';
import { logSettingsUpdate, getRecentAuditLogs } from '$lib/server/audit';

export const load: PageServerLoad = async ({ locals }) => {
	// Load all configurable data
	const [
		{ data: membershipStatuses },
		{ data: membershipTypes },
		{ data: eventTypes },
		{ data: documentCategories },
		{ data: appSettings },
		{ data: emailTemplates }
	] = await Promise.all([
		locals.supabase.from('membership_statuses').select('*').order('sort_order', { ascending: true }),
		locals.supabase.from('membership_types').select('*').order('sort_order', { ascending: true }),
		locals.supabase.from('event_types').select('*').order('sort_order', { ascending: true }),
		locals.supabase.from('document_categories').select('*').order('sort_order', { ascending: true }),
		locals.supabase.from('app_settings').select('*'),
		locals.supabase.from('email_templates').select('template_key, template_name, category').eq('is_active', true).order('category').order('template_name')
	]);

	// Convert settings to object by category
	const settings: Record<string, Record<string, any>> = {};
	for (const setting of appSettings || []) {
		if (!settings[setting.category]) {
			settings[setting.category] = {};
		}
		settings[setting.category][setting.setting_key] = setting.setting_value;
	}

	// Load recent settings audit logs
	const { logs: auditLogs } = await getRecentAuditLogs(50, { resourceType: 'settings' });

	return {
		membershipStatuses: membershipStatuses || [],
		membershipTypes: membershipTypes || [],
		eventTypes: eventTypes || [],
		documentCategories: documentCategories || [],
		settings,
		emailTemplates: emailTemplates || [],
		auditLogs
	};
};

export const actions: Actions = {
	// Membership Status actions
	createStatus: async ({ request, locals }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const displayName = formData.get('display_name') as string;
		const color = formData.get('color') as string;
		const description = formData.get('description') as string;

		if (!name || !displayName) {
			return fail(400, { error: 'Name and display name are required' });
		}

		const { error } = await locals.supabase.from('membership_statuses').insert({
			name: name.toLowerCase().replace(/\s+/g, '_'),
			display_name: displayName,
			color: color || '#6b7280',
			description: description || null
		});

		if (error) {
			console.error('Create status error:', error);
			return fail(500, { error: 'Failed to create status' });
		}

		return { success: 'Status created successfully!' };
	},

	deleteStatus: async ({ request, locals }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;

		const { error } = await locals.supabase.from('membership_statuses').delete().eq('id', id);

		if (error) {
			console.error('Delete status error:', error);
			return fail(500, { error: 'Failed to delete status' });
		}

		return { success: 'Status deleted!' };
	},

	// Membership Type actions
	createType: async ({ request, locals }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const displayName = formData.get('display_name') as string;
		const annualDues = formData.get('annual_dues') as string;
		const description = formData.get('description') as string;

		if (!name || !displayName || !annualDues) {
			return fail(400, { error: 'Name, display name, and annual dues are required' });
		}

		const { error } = await locals.supabase.from('membership_types').insert({
			name: name.toLowerCase().replace(/\s+/g, '_'),
			display_name: displayName,
			annual_dues: parseFloat(annualDues),
			description: description || null
		});

		if (error) {
			console.error('Create type error:', error);
			return fail(500, { error: 'Failed to create membership type' });
		}

		return { success: 'Membership type created successfully!' };
	},

	deleteType: async ({ request, locals }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;

		const { error } = await locals.supabase.from('membership_types').delete().eq('id', id);

		if (error) {
			console.error('Delete type error:', error);
			return fail(500, { error: 'Failed to delete membership type' });
		}

		return { success: 'Membership type deleted!' };
	},

	// Event Type actions
	createEventType: async ({ request, locals }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const displayName = formData.get('display_name') as string;
		const color = formData.get('color') as string;

		if (!name || !displayName) {
			return fail(400, { error: 'Name and display name are required' });
		}

		const { error } = await locals.supabase.from('event_types').insert({
			name: name.toLowerCase().replace(/\s+/g, '_'),
			display_name: displayName,
			color: color || '#3b82f6'
		});

		if (error) {
			console.error('Create event type error:', error);
			return fail(500, { error: 'Failed to create event type' });
		}

		return { success: 'Event type created successfully!' };
	},

	deleteEventType: async ({ request, locals }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;

		const { error } = await locals.supabase.from('event_types').delete().eq('id', id);

		if (error) {
			console.error('Delete event type error:', error);
			return fail(500, { error: 'Failed to delete event type' });
		}

		return { success: 'Event type deleted!' };
	},

	// Document Category actions
	createCategory: async ({ request, locals }) => {
		const formData = await request.formData();
		const name = formData.get('name') as string;
		const displayName = formData.get('display_name') as string;
		const description = formData.get('description') as string;

		if (!name || !displayName) {
			return fail(400, { error: 'Name and display name are required' });
		}

		const { error } = await locals.supabase.from('document_categories').insert({
			name: name.toLowerCase().replace(/\s+/g, '_'),
			display_name: displayName,
			description: description || null
		});

		if (error) {
			console.error('Create category error:', error);
			return fail(500, { error: 'Failed to create document category' });
		}

		return { success: 'Document category created successfully!' };
	},

	deleteCategory: async ({ request, locals }) => {
		const formData = await request.formData();
		const id = formData.get('id') as string;

		const { error } = await locals.supabase.from('document_categories').delete().eq('id', id);

		if (error) {
			console.error('Delete category error:', error);
			return fail(500, { error: 'Failed to delete document category' });
		}

		return { success: 'Document category deleted!' };
	},

	// Update app settings
	updateSettings: async ({ request, locals }) => {
		const { member } = await locals.safeGetSession();

		if (!member || member.role !== 'admin') {
			return fail(403, { error: 'Unauthorized' });
		}

		const formData = await request.formData();
		const category = formData.get('category') as string;

		if (!category) {
			return fail(400, { error: 'Category is required' });
		}

		try {
			// Get existing boolean settings for this category to handle unchecked checkboxes
			// Use supabaseAdmin to bypass RLS
			const { data: existingSettings, error: fetchError } = await supabaseAdmin
				.from('app_settings')
				.select('setting_key, setting_type')
				.eq('category', category);

			if (fetchError) {
				console.error('Error fetching existing settings:', fetchError);
				return fail(500, { error: 'Failed to load existing settings' });
			}

			const existingBooleanKeys = new Set(
				(existingSettings || [])
					.filter(s => s.setting_type === 'boolean')
					.map(s => s.setting_key)
			);

			// Get all settings from form data
			const settingsToUpdate: Array<{ key: string; value: any; type: string }> = [];
			const processedKeys = new Set<string>();

			for (const [key, value] of formData.entries()) {
				if (key !== 'category' && key.startsWith('setting_')) {
					const settingKey = key.replace('setting_', '');
					processedKeys.add(settingKey);
					// Handle checkbox values - they come as 'on' when checked
					const isCheckbox = value === 'on' || existingBooleanKeys.has(settingKey);
					settingsToUpdate.push({
						key: settingKey,
						value: isCheckbox ? (value === 'on' || value === 'true') : value,
						type: isCheckbox ? 'boolean' : 'text'
					});
				}
			}

			// Handle unchecked checkboxes - they don't send any value
			// For any existing boolean setting NOT in the form data, set to false
			for (const booleanKey of existingBooleanKeys) {
				if (!processedKeys.has(booleanKey)) {
					settingsToUpdate.push({
						key: booleanKey,
						value: false,
						type: 'boolean'
					});
				}
			}

			// Update or insert each setting using supabaseAdmin (bypasses RLS)
			for (const setting of settingsToUpdate) {
				// Try to update first
				const { data: existing } = await supabaseAdmin
					.from('app_settings')
					.select('id')
					.eq('category', category)
					.eq('setting_key', setting.key)
					.single();

				if (existing) {
					// Update existing
					const { error: updateError } = await supabaseAdmin
						.from('app_settings')
						.update({
							setting_value: setting.type === 'boolean' ? setting.value : JSON.stringify(setting.value),
							updated_at: new Date().toISOString(),
							updated_by: member.id
						})
						.eq('category', category)
						.eq('setting_key', setting.key);

					if (updateError) {
						console.error('Error updating setting:', setting.key, updateError);
					}
				} else {
					// Insert new setting
					const { error: insertError } = await supabaseAdmin
						.from('app_settings')
						.insert({
							category,
							setting_key: setting.key,
							setting_value: setting.type === 'boolean' ? setting.value : JSON.stringify(setting.value),
							setting_type: setting.type,
							display_name: setting.key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
							updated_at: new Date().toISOString(),
							updated_by: member.id
						});

					if (insertError) {
						console.error('Error inserting setting:', setting.key, insertError);
					}
				}
			}

			// Clear caches if storage settings were updated
			if (category === 'storage') {
				clearS3ClientCache();
			}

			logSettingsUpdate(
				{ id: member.id, email: member.email! },
				category,
				{ changed_settings: settingsToUpdate.map(s => s.key) }
			);

			return { success: 'Settings updated successfully!' };
		} catch (err) {
			console.error('Unexpected error updating settings:', err);
			return fail(500, { error: 'An unexpected error occurred while saving settings' });
		}
	},

	// Test SMTP connection
	testSmtp: async ({ request, locals }) => {
		const { member } = await locals.safeGetSession();
		const formData = await request.formData();
		const testEmail = formData.get('test_email') as string;

		// Use the member's email if no test email is provided
		const recipientEmail = testEmail || member?.email;

		if (!recipientEmail) {
			return fail(400, { error: 'No email address provided for test' });
		}

		// Test SMTP connection and send a test email
		const result = await testSmtpConnection(recipientEmail, member?.id);

		if (!result.success) {
			return fail(400, { error: result.error || 'SMTP test failed' });
		}

		return {
			success: `Test email sent successfully to ${recipientEmail}! Check your inbox.`
		};
	},

	// Test S3/MinIO connection
	testS3: async () => {
		// Clear cache to ensure fresh settings are used
		clearS3ClientCache();

		// Test S3 connection using the actual client
		const result = await testS3Connection();

		if (!result.success) {
			return fail(400, { error: result.error || 'S3 connection test failed' });
		}

		return {
			success: 'S3/MinIO connection successful! Bucket is accessible.'
		};
	},

	// Test email template
	testEmailTemplate: async ({ request, locals, url }) => {
		const { member } = await locals.safeGetSession();

		if (!member?.email) {
			return fail(400, { error: 'No email address found for your account' });
		}

		const formData = await request.formData();
		const templateKey = formData.get('template_key') as string;

		if (!templateKey) {
			return fail(400, { error: 'Template key is required' });
		}

		// Get full member details including member_id
		const { data: fullMember } = await locals.supabase
			.from('members')
			.select('member_id')
			.eq('id', member.id)
			.single();

		const memberId = fullMember?.member_id || 'MUSA-0001';

		// Create sample variables for each template type
		const sampleVariables: Record<string, Record<string, string>> = {
			// Welcome/Auth templates
			welcome: {
				first_name: member.first_name || 'Test',
				last_name: member.last_name || 'User',
				member_id: memberId,
				portal_url: url.origin
			},
			password_reset: {
				first_name: member.first_name || 'Test',
				reset_link: `${url.origin}/reset-password?token=sample-token`
			},
			email_verification: {
				first_name: member.first_name || 'Test',
				verification_link: `${url.origin}/verify?token=sample-token`
			},
			// Event templates
			rsvp_confirmation: {
				first_name: member.first_name || 'Test',
				event_title: 'Monaco USA Annual Gala',
				event_date: 'Saturday, March 15, 2026',
				event_time: '7:00 PM',
				event_location: 'Hotel Hermitage, Monaco',
				guest_count: '2',
				portal_url: `${url.origin}/events`
			},
			waitlist_promotion: {
				first_name: member.first_name || 'Test',
				event_title: 'Monaco USA Annual Gala',
				event_date: 'Saturday, March 15, 2026',
				event_location: 'Hotel Hermitage, Monaco',
				portal_url: `${url.origin}/events`
			},
			event_reminder_24hr: {
				first_name: member.first_name || 'Test',
				event_title: 'Monaco USA Monthly Meetup',
				event_date: 'Tomorrow, January 25, 2026',
				event_time: '6:30 PM',
				event_location: 'Stars\'n\'Bars, Monaco',
				guest_count: '1',
				portal_url: `${url.origin}/events/sample-event-id`
			},
			// Payment/Dues templates
			payment_received: {
				first_name: member.first_name || 'Test',
				amount: '€50.00',
				payment_date: 'January 24, 2026',
				payment_method: 'Bank Transfer',
				new_due_date: 'January 24, 2027',
				member_id: memberId
			},
			dues_reminder_30: {
				first_name: member.first_name || 'Test',
				due_date: 'February 24, 2026',
				amount: '€50.00',
				member_id: memberId,
				account_holder: 'Monaco USA Association',
				bank_name: 'CMB Monaco',
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			},
			dues_reminder_7: {
				first_name: member.first_name || 'Test',
				due_date: 'January 31, 2026',
				amount: '€50.00',
				member_id: memberId,
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			},
			dues_reminder_1: {
				first_name: member.first_name || 'Test',
				due_date: 'January 25, 2026',
				amount: '€50.00',
				member_id: memberId,
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			},
			dues_overdue: {
				first_name: member.first_name || 'Test',
				due_date: 'January 15, 2026',
				amount: '€50.00',
				days_overdue: '9',
				grace_days_remaining: '21',
				member_id: memberId,
				account_holder: 'Monaco USA Association',
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			},
			dues_grace_warning: {
				first_name: member.first_name || 'Test',
				due_date: 'December 24, 2025',
				amount: '€50.00',
				days_overdue: '31',
				grace_days_remaining: '7',
				grace_end_date: 'February 1, 2026',
				member_id: memberId,
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			},
			dues_inactive_notice: {
				first_name: member.first_name || 'Test',
				amount: '€50.00',
				member_id: memberId,
				account_holder: 'Monaco USA Association',
				iban: 'MC00 0000 0000 0000 0000 0000 000',
				portal_url: `${url.origin}/payments`
			}
		};

		// Get variables for this template, or use defaults
		const variables = sampleVariables[templateKey] || {
			first_name: member.first_name || 'Test',
			last_name: member.last_name || 'User',
			portal_url: url.origin
		};

		// Send test email
		const result = await sendTemplatedEmail(templateKey, member.email, variables, {
			recipientId: member.id,
			recipientName: `${member.first_name} ${member.last_name}`,
			baseUrl: url.origin
		});

		if (!result.success) {
			return fail(400, { error: result.error || 'Failed to send test email' });
		}

		return {
			success: `Test email "${templateKey}" sent to ${member.email}`
		};
	},

	// ============================================
	// Poste Mail Server Actions
	// ============================================

	testPoste: async ({ locals }) => {
		// Get Poste settings
		const { data: settings } = await locals.supabase
			.from('app_settings')
			.select('setting_key, setting_value')
			.eq('category', 'poste');

		if (!settings || settings.length === 0) {
			return fail(400, { error: 'Poste mail server not configured. Please save settings first.' });
		}

		const config: Record<string, string> = {};
		for (const s of settings) {
			let value = s.setting_value;
			if (typeof value === 'string') {
				value = value.replace(/^"|"$/g, '');
			}
			config[s.setting_key] = value as string;
		}

		if (!config.poste_api_host || !config.poste_admin_email || !config.poste_admin_password) {
			return fail(400, { error: 'Poste configuration incomplete. Host, admin email, and password are required.' });
		}

		const result = await poste.testConnection({
			host: config.poste_api_host,
			adminEmail: config.poste_admin_email,
			adminPassword: config.poste_admin_password
		});

		if (!result.success) {
			return fail(400, { error: result.error || 'Connection test failed' });
		}

		return { success: 'Connection to Poste mail server successful!' };
	},

	listMailboxes: async ({ locals }) => {
		// Get Poste settings
		const { data: settings } = await locals.supabase
			.from('app_settings')
			.select('setting_key, setting_value')
			.eq('category', 'poste');

		if (!settings || settings.length === 0) {
			return fail(400, { error: 'Poste not configured' });
		}

		const config: Record<string, string> = {};
		for (const s of settings) {
			let value = s.setting_value;
			if (typeof value === 'string') {
				value = value.replace(/^"|"$/g, '');
			}
			config[s.setting_key] = value as string;
		}

		const result = await poste.listMailboxes({
			host: config.poste_api_host,
			adminEmail: config.poste_admin_email,
			adminPassword: config.poste_admin_password
		});

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

		return { mailboxes: result.mailboxes };
	},

	createMailbox: async ({ request, locals }) => {
		const formData = await request.formData();
		const emailPrefix = formData.get('email_prefix') as string;
		const displayName = formData.get('display_name') as string;
		const password = formData.get('password') as string;

		if (!emailPrefix || !displayName) {
			return fail(400, { error: 'Email prefix and display name are required' });
		}

		// Get Poste settings
		const { data: settings } = await locals.supabase
			.from('app_settings')
			.select('setting_key, setting_value')
			.eq('category', 'poste');

		const config: Record<string, string> = {};
		for (const s of settings || []) {
			let value = s.setting_value;
			if (typeof value === 'string') {
				value = value.replace(/^"|"$/g, '');
			}
			config[s.setting_key] = value as string;
		}

		const domain = config.poste_domain || 'monacousa.org';
		const fullEmail = `${emailPrefix}@${domain}`;
		const actualPassword = password || poste.generatePassword();

		const result = await poste.createMailbox(
			{
				host: config.poste_api_host,
				adminEmail: config.poste_admin_email,
				adminPassword: config.poste_admin_password
			},
			{
				email: fullEmail,
				name: displayName,
				password: actualPassword
			}
		);

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

		return {
			success: `Mailbox ${fullEmail} created successfully!`,
			generatedPassword: password ? undefined : actualPassword
		};
	},

	updateMailbox: async ({ request, locals }) => {
		const formData = await request.formData();
		const email = formData.get('email') as string;
		const displayName = formData.get('display_name') as string;
		const newPassword = formData.get('new_password') as string;
		const disabled = formData.get('disabled') === 'true';

		if (!email) {
			return fail(400, { error: 'Email is required' });
		}

		// Get Poste settings
		const { data: settings } = await locals.supabase
			.from('app_settings')
			.select('setting_key, setting_value')
			.eq('category', 'poste');

		const config: Record<string, string> = {};
		for (const s of settings || []) {
			let value = s.setting_value;
			if (typeof value === 'string') {
				value = value.replace(/^"|"$/g, '');
			}
			config[s.setting_key] = value as string;
		}

		const updates: { name?: string; password?: string; disabled?: boolean } = {};
		if (displayName) updates.name = displayName;
		if (newPassword) updates.password = newPassword;
		updates.disabled = disabled;

		const result = await poste.updateMailbox(
			{
				host: config.poste_api_host,
				adminEmail: config.poste_admin_email,
				adminPassword: config.poste_admin_password
			},
			email,
			updates
		);

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

		return { success: `Mailbox ${email} updated successfully!` };
	},

	deleteMailbox: async ({ request, locals }) => {
		const formData = await request.formData();
		const email = formData.get('email') as string;

		if (!email) {
			return fail(400, { error: 'Email is required' });
		}

		// Get Poste settings
		const { data: settings } = await locals.supabase
			.from('app_settings')
			.select('setting_key, setting_value')
			.eq('category', 'poste');

		const config: Record<string, string> = {};
		for (const s of settings || []) {
			let value = s.setting_value;
			if (typeof value === 'string') {
				value = value.replace(/^"|"$/g, '');
			}
			config[s.setting_key] = value as string;
		}

		const result = await poste.deleteMailbox(
			{
				host: config.poste_api_host,
				adminEmail: config.poste_admin_email,
				adminPassword: config.poste_admin_password
			},
			email
		);

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

		return { success: `Mailbox ${email} deleted successfully!` };
	}
};
