<script lang="ts">
	import { onMount } from 'svelte';
	import { browser } from '$app/environment';
	import { PUBLIC_KRATOS_URL } from '$env/static/public';
	import type { PageData } from './$types';
	import type { Identity, Session, Message } from '@ory/client';
	import { kratosAdminClient, kratosClient } from '$lib/kratos';
	import axios from 'axios';
	import IdentityDetailsModal from '$lib/components/modals/IdentityDetailsModal.svelte';
	import IdentityEditModal from '$lib/components/modals/IdentityEditModal.svelte';
	import IdentityCreateModal from '$lib/components/modals/IdentityCreateModal.svelte';
	import SessionDetailsModal from '$lib/components/modals/SessionDetailsModal.svelte';
	import IdentitySessionsModal from '$lib/components/modals/IdentitySessionsModal.svelte';
	import MessageDetailsModal from '$lib/components/modals/MessageDetailsModal.svelte';

	// Configure axios to send credentials (fallback for non-Kratos endpoints)
	const api = axios.create({
		baseURL: PUBLIC_KRATOS_URL,
		withCredentials: true
	});

	let { data }: { data: PageData } = $props();

	// Tab management
	let activeTab = $state<'identities' | 'sessions' | 'recovery' | 'courier' | 'batch'>(
		'identities'
	);

	// Identity management state
	let identities = $state<Identity[]>([]);
	let identityLoading = $state(false);
	let identityError = $state<string | null>(null);
	let selectedIdentity = $state<Identity | null>(null);
	let editingIdentity = $state<Identity | null>(null);
	let showCreateModal = $state(false);
	let identityPage = $state(0);
	let identityPageSize = $state(50);
	let identitySearch = $state('');
	let identityHasMore = $state(true);
	let identitySessionsModal = $state<{ identity: Identity; sessions: Session[] } | null>(null);

	// Session management state
	let sessions = $state<Session[]>([]);
	let sessionLoading = $state(false);
	let sessionError = $state<string | null>(null);
	let selectedSession = $state<Session | null>(null);
	let sessionPage = $state(0);
	let sessionPageSize = $state(50);
	let sessionHasMore = $state(true);

	// Recovery state
	let recoveryLoading = $state(false);
	let recoveryError = $state<string | null>(null);
	let recoveryResult = $state<any>(null);
	let recoveryEmail = $state('');
	let recoveryType = $state<'link' | 'code'>('link');

	// Courier state
	let courierMessages = $state<Message[]>([]);
	let courierLoading = $state(false);
	let courierError = $state<string | null>(null);
	let selectedMessage = $state<Message | null>(null);
	let courierStatus = $state<string>('');
	let courierRecipient = $state('');
	let courierPageToken = $state<string>('');
	let courierPageSize = $state(50);
	let courierHasMore = $state(true);
	let courierNextToken = $state<string | null>(null);

	// Create identity form state
	let createForm = $state({
		schema_id: 'nexus-v2',
		traits: {
			email: '',
			name: { first: '', last: '' },
			profile_type: 'team'
		}
	});

	// Batch operations state
	let batchJsonInput = $state('');
	let batchLoading = $state(false);
	let batchError = $state<string | null>(null);
	let batchResult = $state<any>(null);

	onMount(async () => {
		await loadIdentities();
	});

	// Identity functions
	async function loadIdentities() {
		identityLoading = true;
		identityError = null;

		try {
			const response = await kratosAdminClient.listIdentities({
				page: identityPage,
				perPage: identityPageSize
			});

			identities = response.data;
			// Check if there might be more results
			identityHasMore = response.data.length === identityPageSize;
		} catch (err: any) {
			console.error('Error loading identities:', err);
			if (err.response) {
				identityError = `Failed to load identities: ${err.response.status} ${err.response.statusText}`;
			} else {
				identityError = 'Failed to load identities. Please try again.';
			}
		} finally {
			identityLoading = false;
		}
	}

	async function nextIdentityPage() {
		identityPage++;
		await loadIdentities();
	}

	async function prevIdentityPage() {
		if (identityPage > 0) {
			identityPage--;
			await loadIdentities();
		}
	}

	// CSV Export function
	function exportIdentitiesToCSV() {
		// Create CSV content
		const headers = ['ID', 'Email', 'First Name', 'Last Name', 'Profile Type', 'Verified', 'State', 'Created At', 'Updated At'];
		const rows = filteredIdentities.map(i => [
			i.id,
			i.traits?.email || '',
			i.traits?.name?.first || '',
			i.traits?.name?.last || '',
			i.traits?.profile_type || '',
			hasUnverifiedEmail(i) ? 'No' : 'Yes',
			i.state || '',
			i.created_at || '',
			i.updated_at || ''
		]);

		// Combine headers and rows
		const csvContent = [
			headers.join(','),
			...rows.map(row => row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(','))
		].join('\n');

		// Create blob and download
		const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
		const link = document.createElement('a');
		const url = URL.createObjectURL(blob);

		link.setAttribute('href', url);
		link.setAttribute('download', `identities-${new Date().toISOString().split('T')[0]}.csv`);
		link.style.visibility = 'hidden';

		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
	}

	async function viewIdentity(identity: Identity) {
		identityLoading = true;
		try {
			// Fetch identity with credentials included
			// Valid credential types: oidc, password, totp, webauthn, code
			const response = await kratosAdminClient.getIdentity({
				id: identity.id,
				includeCredential: [
					'oidc',
					'password',
					'totp',
					'webauthn',
					'code'
				]
			});
			selectedIdentity = response.data;
		} catch (err: any) {
			console.error('Error loading identity details:', err);
			selectedIdentity = identity; // Fallback to basic identity
		} finally {
			identityLoading = false;
		}
	}

	function closeModal() {
		selectedIdentity = null;
		editingIdentity = null;
		showCreateModal = false;
		selectedSession = null;
		selectedMessage = null;
		recoveryResult = null;
		identitySessionsModal = null;
		batchResult = null;
	}

	async function deleteIdentity(id: string) {
		if (!confirm('Are you sure you want to delete this identity? This action cannot be undone.')) {
			return;
		}

		try {
			await kratosAdminClient.deleteIdentity({ id });
			await loadIdentities();
			if (selectedIdentity?.id === id) {
				closeModal();
			}
		} catch (err: any) {
			console.error('Error deleting identity:', err);
			if (err.response) {
				alert(`Failed to delete identity: ${err.response.status} ${err.response.statusText}`);
			} else {
				alert('Failed to delete identity. Please try again.');
			}
		}
	}

	async function createIdentity() {
		identityLoading = true;
		identityError = null;

		try {
			await kratosAdminClient.createIdentity({
				createIdentityBody: createForm
			});
			await loadIdentities();
			closeModal();
			// Reset form
			createForm = {
				schema_id: 'nexus-v2',
				traits: {
					email: '',
					name: { first: '', last: '' },
					profile_type: 'team'
				}
			};
		} catch (err: any) {
			console.error('Error creating identity:', err);
			if (err.response) {
				identityError = `Failed to create identity: ${err.response.data?.error?.message || err.response.statusText}`;
			} else {
				identityError = 'Failed to create identity. Please try again.';
			}
		} finally {
			identityLoading = false;
		}
	}

	function startEdit(identity: Identity) {
		editingIdentity = JSON.parse(JSON.stringify(identity)); // Deep clone

		// Ensure metadata_public exists with default structure
		if (editingIdentity && !editingIdentity.metadata_public) {
			editingIdentity.metadata_public = {};
		}

		selectedIdentity = null;
	}

	// Helper function to create JSON Patch operations
	function createJsonPatch(original: Identity, updated: Identity): any[] {
		const patches: any[] = [];

		// Check if traits changed
		if (JSON.stringify(original.traits) !== JSON.stringify(updated.traits)) {
			patches.push({ op: 'replace', path: '/traits', value: updated.traits });
		}

		// Check if state changed
		if (original.state !== updated.state) {
			patches.push({ op: 'replace', path: '/state', value: updated.state });
		}

		// Check if metadata_admin changed
		if (JSON.stringify(original.metadata_admin) !== JSON.stringify(updated.metadata_admin)) {
			patches.push({ op: 'replace', path: '/metadata_admin', value: updated.metadata_admin });
		}

		// Check if metadata_public changed
		if (JSON.stringify(original.metadata_public) !== JSON.stringify(updated.metadata_public)) {
			patches.push({ op: 'replace', path: '/metadata_public', value: updated.metadata_public });
		}

		return patches;
	}

	async function updateIdentity() {
		if (!editingIdentity) return;

		identityLoading = true;
		identityError = null;

		try {
			// Store a reference to the editing identity for type safety
			const currentIdentity = editingIdentity;

			// Find the original identity to compare changes
			const original = identities.find((i) => i.id === currentIdentity.id);

			if (original) {
				// Use PATCH with JSON Patch operations for efficient partial updates
				const patches = createJsonPatch(original, currentIdentity);

				if (patches.length > 0) {
					await kratosAdminClient.patchIdentity({
						id: currentIdentity.id,
						jsonPatch: patches
					});
				}
			} else {
				// Fallback to PUT if we don't have the original
				await kratosAdminClient.updateIdentity({
					id: currentIdentity.id,
					updateIdentityBody: {
						schema_id: currentIdentity.schema_id,
						traits: currentIdentity.traits,
						state: currentIdentity.state || 'active',
						metadata_admin: currentIdentity.metadata_admin,
						metadata_public: currentIdentity.metadata_public
					}
				});
			}

			await loadIdentities();
			closeModal();
		} catch (err: any) {
			console.error('Error updating identity:', err);
			if (err.response) {
				identityError = `Failed to update identity: ${err.response.data?.error?.message || err.response.statusText}`;
			} else {
				identityError = 'Failed to update identity. Please try again.';
			}
		} finally {
			identityLoading = false;
		}
	}

	async function deleteIdentitySessions(id: string) {
		if (!confirm('Are you sure you want to delete all sessions for this identity?')) {
			return;
		}

		try {
			await api.delete(`/admin/identities/${id}/sessions`);
			alert('All sessions deleted successfully');
		} catch (err: any) {
			console.error('Error deleting sessions:', err);
			alert(`Failed to delete sessions: ${err.response?.data?.error?.message || 'Unknown error'}`);
		}
	}

	async function viewIdentitySessions(identity: Identity) {
		identityLoading = true;
		try {
			const response = await api.get(`/admin/identities/${identity.id}/sessions`);
			identitySessionsModal = {
				identity,
				sessions: response.data
			};
		} catch (err: any) {
			console.error('Error loading identity sessions:', err);
			alert(`Failed to load sessions: ${err.response?.data?.error?.message || 'Unknown error'}`);
		} finally {
			identityLoading = false;
		}
	}

	async function deleteCredential(identityId: string, type: string, identifier?: string) {
		const confirmMsg = identifier
			? `Are you sure you want to delete the ${type} credential (${identifier})?`
			: `Are you sure you want to delete the ${type} credential?`;

		if (!confirm(confirmMsg)) {
			return;
		}

		try {
			const params = identifier ? { identifier } : {};
			await api.delete(`/admin/identities/${identityId}/credentials/${type}`, { params });
			alert('Credential deleted successfully');

			// Refresh the identity view
			if (selectedIdentity) {
				await viewIdentity(selectedIdentity);
			}
		} catch (err: any) {
			console.error('Error deleting credential:', err);
			alert(
				`Failed to delete credential: ${err.response?.data?.error?.message || 'Unknown error'}`
			);
		}
	}

	async function resendVerificationEmail(identity: Identity) {
		if (!identity.traits?.email) {
			alert('No email address found for this identity');
			return;
		}

		if (!confirm(`Send verification email to ${identity.traits.email}?`)) {
			return;
		}

		identityLoading = true;
		try {
			// Step 1: Create a new verification flow
			const flowResponse = await kratosClient.createBrowserVerificationFlow();
			const flow = flowResponse.data;

			// Step 2: Extract CSRF token from flow UI
			const csrfNode = flow.ui.nodes.find(
				(node: any) => node.attributes?.name === 'csrf_token'
			);
			const csrfToken = (csrfNode?.attributes as any)?.value;

			if (!csrfToken) {
				throw new Error('CSRF token not found in verification flow');
			}

			// Step 3: Submit the email with CSRF token to trigger verification email
			await kratosClient.updateVerificationFlow({
				flow: flow.id,
				updateVerificationFlowBody: {
					method: 'code',
					email: identity.traits.email,
					csrf_token: csrfToken
				}
			});

			alert(`Verification email sent successfully to ${identity.traits.email}`);
		} catch (err: any) {
			console.error('Error sending verification email:', err);
			alert(
				`Failed to send verification email: ${err.response?.data?.error?.message || err.message || 'Unknown error'}`
			);
		} finally {
			identityLoading = false;
		}
	}

	// Helper function to check if an identity has an unverified email
	function hasUnverifiedEmail(identity: Identity): boolean {
		return identity.verifiable_addresses?.some((addr) => !addr.verified) || false;
	}

	// Session functions
	async function loadSessions() {
		sessionLoading = true;
		sessionError = null;

		try {
			const url = `/admin/sessions?page=${sessionPage}&per_page=${sessionPageSize}&expand=identity`;
			const response = await api.get(url);
			sessions = response.data;
			// Check if there might be more results
			sessionHasMore = response.data.length === sessionPageSize;
		} catch (err: any) {
			console.error('Error loading sessions:', err);
			if (err.response) {
				sessionError = `Failed to load sessions: ${err.response.status} ${err.response.statusText}`;
			} else {
				sessionError = 'Failed to load sessions. Please try again.';
			}
		} finally {
			sessionLoading = false;
		}
	}

	async function nextSessionPage() {
		sessionPage++;
		await loadSessions();
	}

	async function prevSessionPage() {
		if (sessionPage > 0) {
			sessionPage--;
			await loadSessions();
		}
	}

	async function viewSession(session: Session) {
		sessionLoading = true;
		try {
			// Fetch full session details with all expandables
			const response = await api.get(`/admin/sessions/${session.id}`, {
				params: {
					expand: ['identity', 'devices']
				}
			});
			selectedSession = response.data;
		} catch (err: any) {
			console.error('Error loading session details:', err);
			// Fallback to the session from the list if detailed fetch fails
			selectedSession = session;
		} finally {
			sessionLoading = false;
		}
	}

	async function deleteSession(id: string) {
		if (!confirm('Are you sure you want to delete this session?')) {
			return;
		}

		try {
			await api.delete(`/admin/sessions/${id}`);
			await loadSessions();
			if (selectedSession?.id === id) {
				closeModal();
			}
		} catch (err: any) {
			console.error('Error deleting session:', err);
			alert(`Failed to delete session: ${err.response?.data?.error?.message || 'Unknown error'}`);
		}
	}

	async function extendSession(id: string) {
		try {
			await api.patch(`/admin/sessions/${id}/extend`);
			await loadSessions();
			alert('Session extended successfully');
		} catch (err: any) {
			console.error('Error extending session:', err);
			alert(`Failed to extend session: ${err.response?.data?.error?.message || 'Unknown error'}`);
		}
	}

	// Recovery functions
	async function createRecovery() {
		if (!recoveryEmail) {
			alert('Please enter an email address');
			return;
		}

		recoveryLoading = true;
		recoveryError = null;
		recoveryResult = null;

		try {
			const endpoint = recoveryType === 'link' ? '/admin/recovery/link' : '/admin/recovery/code';
			const response = await api.post(endpoint, {
				identity_id: identities.find((i) => i.traits?.email === recoveryEmail)?.id,
				expires_in: '1h'
			});

			recoveryResult = response.data;
		} catch (err: any) {
			console.error('Error creating recovery:', err);
			if (err.response) {
				recoveryError = `Failed to create recovery: ${err.response.data?.error?.message || err.response.statusText}`;
			} else {
				recoveryError = 'Failed to create recovery. Please try again.';
			}
		} finally {
			recoveryLoading = false;
		}
	}

	// Courier functions
	async function loadCourierMessages() {
		courierLoading = true;
		courierError = null;

		try {
			const params: any = {
				page_size: courierPageSize
			};
			// Only add page_token if we have one (for pagination)
			if (courierPageToken) params.page_token = courierPageToken;
			if (courierStatus) params.status = courierStatus;
			if (courierRecipient) params.recipient = courierRecipient;

			const response = await api.get('/admin/courier/messages', { params });

			courierMessages = response.data;
			// Check if there's a next token for pagination
			courierNextToken = response.headers['x-next-page-token'] || null;
			courierHasMore = !!courierNextToken;
		} catch (err: any) {
			console.error('Error loading courier messages:', err);
			if (err.response) {
				courierError = `Failed to load messages: ${err.response.status} ${err.response.statusText}`;
			} else {
				courierError = 'Failed to load messages. Please try again.';
			}
		} finally {
			courierLoading = false;
		}
	}

	async function nextCourierPage() {
		if (courierNextToken) {
			courierPageToken = courierNextToken;
			await loadCourierMessages();
		}
	}

	async function resetCourierPage() {
		courierPageToken = '';
		courierNextToken = null;
		await loadCourierMessages();
	}

	async function viewMessage(message: Message) {
		courierLoading = true;
		try {
			// Fetch full message details with all fields
			const response = await api.get(`/admin/courier/messages/${message.id}`);
			selectedMessage = response.data;
		} catch (err: any) {
			console.error('Error loading message details:', err);
			// Fallback to the message from the list if detailed fetch fails
			selectedMessage = message;
		} finally {
			courierLoading = false;
		}
	}

	// Batch operations functions
	async function batchCreateIdentities() {
		if (!batchJsonInput.trim()) {
			alert('Please enter JSON data for batch creation');
			return;
		}

		batchLoading = true;
		batchError = null;
		batchResult = null;

		try {
			// Parse the JSON input
			const identitiesData = JSON.parse(batchJsonInput);

			// Validate it's an array
			if (!Array.isArray(identitiesData)) {
				batchError = 'Input must be an array of identity objects';
				return;
			}

			// Call the batch PATCH endpoint
			const response = await api.patch('/admin/identities', { identities: identitiesData });

			batchResult = response.data;
			await loadIdentities();

			// Clear the input on success
			batchJsonInput = '';
		} catch (err: any) {
			console.error('Error batch creating identities:', err);
			if (err.response) {
				batchError = `Failed to batch create identities: ${err.response.data?.error?.message || err.response.statusText}`;
			} else if (err instanceof SyntaxError) {
				batchError = `Invalid JSON: ${err.message}`;
			} else {
				batchError = err.message || 'Failed to batch create identities. Please try again.';
			}
		} finally {
			batchLoading = false;
		}
	}

	// Tab change handler
	async function changeTab(tab: typeof activeTab) {
		activeTab = tab;

		if (tab === 'sessions' && sessions.length === 0) {
			await loadSessions();
		} else if (tab === 'courier' && courierMessages.length === 0) {
			await loadCourierMessages();
		}
	}

	// Computed filtered identities
	const filteredIdentities = $derived(
		identitySearch
			? identities.filter(
					(i) =>
						i.traits?.email?.toLowerCase().includes(identitySearch.toLowerCase()) ||
						i.traits?.name?.first?.toLowerCase().includes(identitySearch.toLowerCase()) ||
						i.traits?.name?.last?.toLowerCase().includes(identitySearch.toLowerCase()) ||
						i.id.toLowerCase().includes(identitySearch.toLowerCase())
				)
			: identities
	);
</script>

<svelte:head>
	<title>Admin Dashboard - Nexus Nexus</title>
</svelte:head>

<div class="min-h-screen bg-slate-100 py-8">
	<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
		<div class="mb-8">
			<h1 class="text-3xl font-bold text-slate-900">Admin Dashboard</h1>
			<p class="mt-2 text-sm text-gray-600">
				Logged in as: {data.session?.identity?.traits?.email || 'Unknown'}
			</p>
		</div>

		<!-- Tab Navigation -->
		<div class="mb-6">
			<nav class="flex space-x-4" aria-label="Tabs">
				<button
					onclick={() => changeTab('identities')}
					class="rounded-md px-3 py-2 text-sm font-medium"
					class:bg-blue-100={activeTab === 'identities'}
					class:text-blue-700={activeTab === 'identities'}
					class:text-gray-500={activeTab !== 'identities'}
					class:hover:text-gray-700={activeTab !== 'identities'}
				>
					Identities
				</button>
				<button
					onclick={() => changeTab('sessions')}
					class="rounded-md px-3 py-2 text-sm font-medium"
					class:bg-blue-100={activeTab === 'sessions'}
					class:text-blue-700={activeTab === 'sessions'}
					class:text-gray-500={activeTab !== 'sessions'}
					class:hover:text-gray-700={activeTab !== 'sessions'}
				>
					Sessions
				</button>
				<button
					onclick={() => changeTab('recovery')}
					class="rounded-md px-3 py-2 text-sm font-medium"
					class:bg-blue-100={activeTab === 'recovery'}
					class:text-blue-700={activeTab === 'recovery'}
					class:text-gray-500={activeTab !== 'recovery'}
					class:hover:text-gray-700={activeTab !== 'recovery'}
				>
					Recovery
				</button>
				<button
					onclick={() => changeTab('courier')}
					class="rounded-md px-3 py-2 text-sm font-medium"
					class:bg-blue-100={activeTab === 'courier'}
					class:text-blue-700={activeTab === 'courier'}
					class:text-gray-500={activeTab !== 'courier'}
					class:hover:text-gray-700={activeTab !== 'courier'}
				>
					Messages
				</button>
				<button
					onclick={() => changeTab('batch')}
					class="rounded-md px-3 py-2 text-sm font-medium"
					class:bg-blue-100={activeTab === 'batch'}
					class:text-blue-700={activeTab === 'batch'}
					class:text-gray-500={activeTab !== 'batch'}
					class:hover:text-gray-700={activeTab !== 'batch'}
				>
					Batch Operations
				</button>
			</nav>
		</div>

		<!-- Identities Tab -->
		{#if activeTab === 'identities'}
			<div class="rounded-lg bg-slate-50 shadow-md">
				<div class="border-b border-slate-200 px-6 py-4">
					<div class="flex items-center justify-between">
						<h2 class="text-xl font-semibold text-slate-900">User Identities</h2>
						<div class="flex space-x-2">
							<button
								onclick={exportIdentitiesToCSV}
								class="rounded-md bg-purple-600 px-4 py-2 text-sm font-medium text-white hover:bg-purple-700"
								title="Export filtered identities to CSV"
							>
								Export CSV
							</button>
							<button
								onclick={() => (showCreateModal = true)}
								class="rounded-md bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700"
							>
								Create Identity
							</button>
							<button
								onclick={loadIdentities}
								class="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
							>
								Refresh
							</button>
						</div>
					</div>
					<div class="mt-4">
						<input
							type="text"
							bind:value={identitySearch}
							placeholder="Search by email, name, or ID..."
							class="w-full rounded-lg border border-gray-300 px-4 py-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
						/>
					</div>
				</div>

				<div class="px-6 py-4">
					{#if identityLoading}
						<p class="text-center text-gray-500">Loading identities...</p>
					{:else if identityError}
						<div class="rounded-lg bg-red-50 p-4">
							<p class="text-sm text-red-800">{identityError}</p>
						</div>
					{:else if filteredIdentities.length === 0}
						<p class="text-center text-gray-500">No identities found.</p>
					{:else}
						<div class="overflow-x-auto">
							<table class="min-w-full divide-y divide-slate-200">
								<thead class="bg-slate-100">
									<tr>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Email
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Name
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Verified
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Created
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											State
										</th>
										<th
											class="px-4 py-3 text-right text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Actions
										</th>
									</tr>
								</thead>
								<tbody class="divide-y divide-slate-200 bg-white">
									{#each filteredIdentities as identity (identity.id)}
										<tr class="hover:bg-slate-50">
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-900">
												{identity.traits?.email || 'N/A'}
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-900">
												{#if identity.traits?.name}
													{identity.traits.name.first || ''} {identity.traits.name.last || ''}
												{:else}
													N/A
												{/if}
											</td>
											<td class="px-4 py-4 whitespace-nowrap">
												{#if hasUnverifiedEmail(identity)}
													<span
														class="inline-flex rounded-full bg-yellow-100 px-2 text-xs leading-5 font-semibold text-yellow-800"
													>
														Unverified
													</span>
												{:else}
													<span
														class="inline-flex rounded-full bg-green-100 px-2 text-xs leading-5 font-semibold text-green-800"
													>
														Verified
													</span>
												{/if}
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-500">
												{new Date(identity.created_at || '').toLocaleDateString()}
											</td>
											<td class="px-4 py-4 whitespace-nowrap">
												<span
													class="inline-flex rounded-full px-2 text-xs leading-5 font-semibold"
													class:bg-green-100={identity.state === 'active'}
													class:text-green-800={identity.state === 'active'}
													class:bg-gray-100={identity.state !== 'active'}
													class:text-gray-800={identity.state !== 'active'}
												>
													{identity.state || 'unknown'}
												</span>
											</td>
											<td class="space-x-2 px-4 py-4 text-right text-sm whitespace-nowrap">
												<button
													onclick={() => viewIdentity(identity)}
													class="text-blue-600 hover:text-blue-900"
												>
													View
												</button>
												<button
													onclick={() => startEdit(identity)}
													class="text-green-600 hover:text-green-900"
												>
													Edit
												</button>
												{#if hasUnverifiedEmail(identity)}
													<button
														onclick={() => resendVerificationEmail(identity)}
														class="text-orange-600 hover:text-orange-900"
														title="Resend verification email"
													>
														Verify
													</button>
												{/if}
												<button
													onclick={() => viewIdentitySessions(identity)}
													class="text-purple-600 hover:text-purple-900"
												>
													Sessions
												</button>
												<button
													onclick={() => deleteIdentitySessions(identity.id)}
													class="text-yellow-600 hover:text-yellow-900"
												>
													End All
												</button>
												<button
													onclick={() => deleteIdentity(identity.id)}
													class="text-red-600 hover:text-red-900"
												>
													Delete
												</button>
											</td>
										</tr>
									{/each}
								</tbody>
							</table>
						</div>

						<!-- Pagination Controls -->
						{#if browser && !identitySearch}
							<div class="mt-4 flex items-center justify-between border-t border-slate-200 pt-4">
								<div class="text-sm text-slate-700">
									Page {identityPage + 1} ({identities.length} identities)
								</div>
								<div class="flex space-x-2">
									<button
										onclick={prevIdentityPage}
										disabled={identityPage === 0}
										class="rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
									>
										Previous
									</button>
									<button
										onclick={nextIdentityPage}
										disabled={!identityHasMore}
										class="rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
									>
										Next
									</button>
								</div>
							</div>
						{/if}
					{/if}
				</div>
			</div>
		{/if}

		<!-- Sessions Tab -->
		{#if activeTab === 'sessions'}
			<div class="rounded-lg bg-slate-50 shadow-md">
				<div class="border-b border-slate-200 px-6 py-4">
					<div class="flex items-center justify-between">
						<h2 class="text-xl font-semibold text-slate-900">Active Sessions</h2>
						<button
							onclick={loadSessions}
							class="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
						>
							Refresh
						</button>
					</div>
				</div>

				<div class="px-6 py-4">
					{#if sessionLoading}
						<p class="text-center text-gray-500">Loading sessions...</p>
					{:else if sessionError}
						<div class="rounded-lg bg-red-50 p-4">
							<p class="text-sm text-red-800">{sessionError}</p>
						</div>
					{:else if sessions.length === 0}
						<p class="text-center text-gray-500">No active sessions found.</p>
					{:else}
						<div class="overflow-x-auto">
							<table class="min-w-full divide-y divide-slate-200">
								<thead class="bg-slate-100">
									<tr>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											User Email
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Session ID
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Issued At
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Expires At
										</th>
										<th
											class="px-4 py-3 text-right text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Actions
										</th>
									</tr>
								</thead>
								<tbody class="divide-y divide-slate-200 bg-white">
							{#each sessions as session (session.id)}
								<tr class="hover:bg-slate-50">
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-900">
												{session.identity?.traits?.email || 'N/A'}
											</td>
											<td class="px-4 py-4 font-mono text-sm whitespace-nowrap text-gray-600">
												{session.id.substring(0, 8)}...
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-500">
												{new Date(session.issued_at || '').toLocaleString()}
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-500">
												{new Date(session.expires_at || '').toLocaleString()}
											</td>
											<td class="space-x-2 px-4 py-4 text-right text-sm whitespace-nowrap">
												<button
													onclick={() => viewSession(session)}
													class="text-blue-600 hover:text-blue-900"
												>
													View
												</button>
												<button
													onclick={() => extendSession(session.id)}
													class="text-green-600 hover:text-green-900"
												>
													Extend
												</button>
												<button
													onclick={() => deleteSession(session.id)}
													class="text-red-600 hover:text-red-900"
												>
													Revoke
												</button>
											</td>
										</tr>
									{/each}
								</tbody>
							</table>
						</div>

						<!-- Pagination Controls -->
						{#if browser}
							<div class="mt-4 flex items-center justify-between border-t border-slate-200 pt-4">
								<div class="text-sm text-slate-700">
									Page {sessionPage + 1} ({sessions.length} sessions)
								</div>
								<div class="flex space-x-2">
									<button
										onclick={prevSessionPage}
										disabled={sessionPage === 0}
										class="rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
									>
										Previous
									</button>
									<button
										onclick={nextSessionPage}
										disabled={!sessionHasMore}
										class="rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
									>
										Next
									</button>
								</div>
							</div>
						{/if}
					{/if}
				</div>
			</div>
		{/if}

		<!-- Recovery Tab -->
		{#if activeTab === 'recovery'}
			<div class="rounded-lg bg-slate-50 shadow-md">
				<div class="border-b border-slate-200 px-6 py-4">
					<h2 class="text-xl font-semibold text-slate-900">Account Recovery</h2>
					<p class="mt-1 text-sm text-slate-600">Generate recovery links or codes for users</p>
				</div>

				<div class="px-6 py-4">
					<div class="max-w-md">
						<div class="mb-4">
							<label for="recovery-email" class="mb-1 block text-sm font-medium text-gray-700">
								User Email
							</label>
							<input
								id="recovery-email"
								type="email"
								bind:value={recoveryEmail}
								placeholder="user@example.com"
								class="w-full rounded-lg border border-gray-300 px-4 py-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
							/>
						</div>

						<div class="mb-4">
							<label for="recovery-type" class="mb-1 block text-sm font-medium text-gray-700">
								Recovery Type
							</label>
							<select
								id="recovery-type"
								bind:value={recoveryType}
								class="w-full rounded-lg border border-gray-300 px-4 py-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
							>
								<option value="link">Recovery Link</option>
								<option value="code">Recovery Code</option>
							</select>
						</div>

						<button
							onclick={createRecovery}
							disabled={recoveryLoading}
							class="w-full rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 disabled:opacity-50"
						>
							{recoveryLoading ? 'Generating...' : 'Generate Recovery'}
						</button>

						{#if recoveryError}
							<div class="mt-4 rounded-lg bg-red-50 p-4">
								<p class="text-sm text-red-800">{recoveryError}</p>
							</div>
						{/if}

						{#if recoveryResult}
							<div class="mt-4 rounded-lg bg-green-50 p-4">
								<p class="mb-2 text-sm font-medium text-green-800">
									Recovery generated successfully!
								</p>
								<div class="rounded bg-white p-3">
									<pre class="overflow-x-auto text-xs text-gray-800">{JSON.stringify(
											recoveryResult,
											null,
											2
										)}</pre>
								</div>
								<button
									onclick={() => {
										navigator.clipboard.writeText(
											recoveryResult.recovery_link || recoveryResult.recovery_code
										);
										alert('Copied to clipboard!');
									}}
									class="mt-2 rounded bg-green-600 px-3 py-1 text-xs text-white hover:bg-green-700"
								>
									Copy to Clipboard
								</button>
							</div>
						{/if}
					</div>
				</div>
			</div>
		{/if}

		<!-- Courier Messages Tab -->
		{#if activeTab === 'courier'}
			<div class="rounded-lg bg-slate-50 shadow-md">
				<div class="border-b border-slate-200 px-6 py-4">
					<div class="flex items-center justify-between">
						<h2 class="text-xl font-semibold text-slate-900">Courier Messages</h2>
						<button
							onclick={loadCourierMessages}
							class="rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700"
						>
							Refresh
						</button>
					</div>
					<div class="mt-4 flex space-x-4">
						<input
							type="text"
							bind:value={courierRecipient}
							placeholder="Filter by recipient email..."
							class="flex-1 rounded-lg border border-gray-300 px-4 py-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
						/>
						<select
							bind:value={courierStatus}
							onchange={() => {
								resetCourierPage();
							}}
							class="rounded-lg border border-gray-300 px-4 py-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
						>
							<option value="">All Statuses</option>
							<option value="queued">Queued</option>
							<option value="sent">Sent</option>
							<option value="processing">Processing</option>
							<option value="abandoned">Abandoned</option>
						</select>
					</div>
				</div>

				<div class="px-6 py-4">
					{#if courierLoading}
						<p class="text-center text-gray-500">Loading messages...</p>
					{:else if courierError}
						<div class="rounded-lg bg-red-50 p-4">
							<p class="text-sm text-red-800">{courierError}</p>
						</div>
					{:else if courierMessages.length === 0}
						<p class="text-center text-gray-500">No messages found.</p>
					{:else}
						<div class="overflow-x-auto">
							<table class="min-w-full divide-y divide-slate-200">
								<thead class="bg-slate-100">
									<tr>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Recipient
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Subject
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Type
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Status
										</th>
										<th
											class="px-4 py-3 text-left text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Created
										</th>
										<th
											class="px-4 py-3 text-right text-xs font-medium tracking-wider text-slate-600 uppercase"
										>
											Actions
										</th>
									</tr>
								</thead>
								<tbody class="divide-y divide-slate-200 bg-white">
							{#each courierMessages as message (message.id)}
								<tr class="hover:bg-slate-50">
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-900">
												{message.recipient || 'N/A'}
											</td>
											<td class="px-4 py-4 text-sm text-gray-900">
												{message.subject || 'N/A'}
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-500">
												{message.template_type || message.channel || 'N/A'}
											</td>
											<td class="px-4 py-4 whitespace-nowrap">
												<span
													class="inline-flex rounded-full px-2 text-xs leading-5 font-semibold"
													class:bg-green-100={message.status === 'sent'}
													class:text-green-800={message.status === 'sent'}
													class:bg-yellow-100={message.status === 'queued' ||
														message.status === 'processing'}
													class:text-yellow-800={message.status === 'queued' ||
														message.status === 'processing'}
													class:bg-red-100={message.status === 'abandoned'}
													class:text-red-800={message.status === 'abandoned'}
												>
													{message.status || 'unknown'}
												</span>
											</td>
											<td class="px-4 py-4 text-sm whitespace-nowrap text-gray-500">
												{message.created_at ? new Date(message.created_at).toLocaleString() : 'N/A'}
											</td>
											<td class="px-4 py-4 text-right text-sm whitespace-nowrap">
												<button
													onclick={() => viewMessage(message)}
													class="text-blue-600 hover:text-blue-900"
												>
													View
												</button>
											</td>
										</tr>
									{/each}
								</tbody>
							</table>
						</div>

						<!-- Pagination Controls -->
						{#if browser}
							<div class="mt-4 flex items-center justify-between border-t border-slate-200 pt-4">
								<div class="text-sm text-slate-700">
									{courierMessages.length} messages
									{#if courierPageToken}
										<button
											onclick={resetCourierPage}
											class="ml-2 text-blue-600 hover:text-blue-900"
										>
											(Reset to first page)
										</button>
									{/if}
								</div>
								<button
									onclick={nextCourierPage}
									disabled={!courierHasMore}
									class="rounded-md bg-slate-200 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-300 disabled:opacity-50 disabled:cursor-not-allowed"
								>
									Next Page
								</button>
							</div>
						{/if}
					{/if}
				</div>
			</div>
		{/if}

		<!-- Batch Operations Tab -->
		{#if activeTab === 'batch'}
			<div class="rounded-lg bg-slate-50 shadow-md">
				<div class="border-b border-slate-200 px-6 py-4">
					<h2 class="text-xl font-semibold text-slate-900">Batch Identity Operations</h2>
					<p class="mt-1 text-sm text-slate-600">
						Create multiple identities at once by providing JSON data
					</p>
				</div>

				<div class="px-6 py-4">
					<div class="max-w-4xl">
						<div class="mb-4">
							<label for="batch-json" class="mb-1 block text-sm font-medium text-gray-700">
								Identity JSON Array
							</label>
							<p class="mb-2 text-xs text-gray-500">
								Provide an array of identity objects. Each identity should have schema_id and
								traits.
							</p>
							<textarea
								id="batch-json"
								bind:value={batchJsonInput}
								placeholder={`[\n  {\n    "schema_id": "default",\n    "traits": {\n      "email": "user1@example.com",\n      "name": {\n        "first": "John",\n        "last": "Doe"\n      }\n    }\n  },\n  {\n    "schema_id": "default",\n    "traits": {\n      "email": "user2@example.com",\n      "name": {\n        "first": "Jane",\n        "last": "Smith"\n      }\n    }\n  }\n]`}
								rows="15"
								class="w-full rounded-lg border border-gray-300 px-4 py-2 font-mono text-sm focus:border-blue-500 focus:ring-2 focus:ring-blue-500"
							></textarea>
						</div>

						<button
							onclick={batchCreateIdentities}
							disabled={batchLoading}
							class="w-full rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 disabled:opacity-50"
						>
							{batchLoading ? 'Creating Identities...' : 'Batch Create Identities'}
						</button>

						{#if batchError}
							<div class="mt-4 rounded-lg bg-red-50 p-4">
								<p class="text-sm text-red-800">{batchError}</p>
							</div>
						{/if}

						{#if batchResult}
							<div class="mt-4 rounded-lg bg-green-50 p-4">
								<p class="mb-2 text-sm font-medium text-green-800">
									Batch operation completed successfully!
								</p>
								<div class="rounded bg-white p-3">
									<pre class="overflow-x-auto text-xs text-gray-800">{JSON.stringify(
											batchResult,
											null,
											2
										)}</pre>
								</div>
								<button
									onclick={() => (batchResult = null)}
									class="mt-2 rounded bg-blue-600 px-3 py-1 text-xs text-white hover:bg-blue-700"
								>
									Clear Result
								</button>
							</div>
						{/if}

						<div class="mt-6 rounded-lg bg-blue-50 p-4">
							<h3 class="mb-2 text-sm font-medium text-blue-900">Example JSON Format</h3>
							<pre class="overflow-x-auto text-xs text-blue-800">{`[
  {
    "schema_id": "default",
    "traits": {
      "email": "user@example.com",
      "name": {
        "first": "First",
        "last": "Last"
      }
    }
  }
]`}</pre>
						</div>
					</div>
				</div>
			</div>
		{/if}
	</div>
</div>

<!-- Modals -->
<IdentityDetailsModal
	identity={selectedIdentity}
	onClose={closeModal}
	onDeleteCredential={deleteCredential}
/>

<IdentityEditModal
	identity={editingIdentity}
	onClose={closeModal}
	onSave={updateIdentity}
	loading={identityLoading}
	error={identityError}
/>

<IdentityCreateModal
	open={showCreateModal}
	form={createForm}
	onClose={closeModal}
	onCreate={createIdentity}
	loading={identityLoading}
	error={identityError}
/>

<SessionDetailsModal session={selectedSession} onClose={closeModal} />

<IdentitySessionsModal
	data={identitySessionsModal}
	onClose={closeModal}
	onViewSession={(session) => {
		selectedSession = session;
		identitySessionsModal = null;
	}}
	onExtendSession={extendSession}
	onDeleteSession={deleteSession}
/>

<MessageDetailsModal message={selectedMessage} onClose={closeModal} />
