<script lang="ts">
	import { ae_util } from '$lib/ae_utils/ae_utils';

	interface MeetingEvent {
		timestamp: string;
		action: string;
		details: { full_name?: string };
	}

	interface MeetingParticipant {
		displayName: string;
		role: string;
	}

	interface MeetingReport {
		meeting_id: string;
		room_name: string;
		start_time: string;
		final_duration: string;
		final_participant_count: number;
		final_participants: MeetingParticipant[];
		events: MeetingEvent[];
	}

	interface Props {
		data: { streamed: { meetings: Promise<MeetingReport[]> } };
	}
	let { data }: Props = $props();

	// --- Data state ---
	// Resolve the streamed promise into reactive state so we can filter and export it.
	let meetings_all = $state<MeetingReport[]>([]);
	let meetings_loading = $state(true);
	let meetings_error = $state<string | null>(null);

	$effect(() => {
		meetings_loading = true;
		meetings_error = null;
		data.streamed.meetings
			.then((m: MeetingReport[]) => {
				meetings_all = m ?? [];
				meetings_loading = false;
			})
			.catch((err: Error) => {
				meetings_error = err.message;
				meetings_loading = false;
			});
	});

	// --- Filter state ---
	// Default 0 so historical logs (which lack an init record and have count=0) are visible.
	// Once logging is fully established, this can be raised to 1 to hide empty/test meetings.
	let filter_min_participants = $state(0);
	let filter_room_name = $state('');
	let filter_date_from = $state('');
	let filter_date_to = $state('');

	let filters_are_modified = $derived(
		filter_min_participants !== 0 ||
		filter_room_name !== '' ||
		filter_date_from !== '' ||
		filter_date_to !== ''
	);

	function reset_filters() {
		filter_min_participants = 0;
		filter_room_name = '';
		filter_date_from = '';
		filter_date_to = '';
	}

	// --- Derived: filtered meetings ---
	let meetings_filtered = $derived.by(() => {
		return meetings_all.filter((m) => {
			if ((m.final_participant_count ?? 0) < filter_min_participants) return false;
			if (filter_room_name && !m.room_name?.toLowerCase().includes(filter_room_name.toLowerCase())) return false;
			if (filter_date_from) {
				if (Date.parse(m.start_time) < Date.parse(filter_date_from)) return false;
			}
			if (filter_date_to) {
				// Include full end-of-day by appending T23:59:59 to the date string
				if (Date.parse(m.start_time) > Date.parse(filter_date_to + 'T23:59:59.999')) return false;
			}
			return true;
		});
	});

	// --- Summary stats ---
	function parse_duration_seconds(d: string): number {
		if (!d) return 0;
		const parts = d.split(':').map(Number);
		return (parts[0] ?? 0) * 3600 + (parts[1] ?? 0) * 60 + (parts[2] ?? 0);
	}

	function format_seconds(total: number): string {
		const h = Math.floor(total / 3600).toString().padStart(2, '0');
		const m = Math.floor((total % 3600) / 60).toString().padStart(2, '0');
		const s = Math.floor(total % 60).toString().padStart(2, '0');
		return `${h}:${m}:${s}`;
	}

	let summary = $derived.by(() => {
		const count = meetings_filtered.length;
		const total_participants = meetings_filtered.reduce((sum, m) => sum + (m.final_participant_count ?? 0), 0);
		const total_secs = meetings_filtered.reduce((sum, m) => sum + parse_duration_seconds(m.final_duration), 0);
		const avg_secs = count > 0 ? Math.round(total_secs / count) : 0;
		return {
			count,
			total_participants,
			avg_duration: format_seconds(avg_secs),
			total_duration: format_seconds(total_secs)
		};
	});

	// --- Accordion state ---
	let open_accordions = $state<{ [key: string]: boolean }>({});

	function toggle_accordion(meeting_id: string) {
		open_accordions[meeting_id] = !open_accordions[meeting_id];
	}

	// --- Export ---
	function download_file(content: string, filename: string, mime: string) {
		const blob = new Blob([content], { type: mime });
		const url = URL.createObjectURL(blob);
		const a = document.createElement('a');
		a.href = url;
		a.download = filename;
		document.body.appendChild(a);
		a.click();
		document.body.removeChild(a);
		URL.revokeObjectURL(url);
	}

	function export_csv() {
		const rows: string[][] = [
			['Meeting ID', 'Room Name', 'Start Time', 'Duration', 'Participant Count']
		];
		for (const m of meetings_filtered) {
			rows.push([
				m.meeting_id ?? '',
				m.room_name ?? '',
				m.start_time ? new Date(m.start_time).toISOString() : '',
				m.final_duration ?? '',
				String(m.final_participant_count ?? 0)
			]);
		}
		const csv = rows
			.map((r) => r.map((cell) => `"${String(cell).replace(/"/g, '""')}"`).join(','))
			.join('\n');
		download_file(csv, 'jitsi_meeting_report.csv', 'text/csv;charset=utf-8;');
	}

	function export_json() {
		download_file(
			JSON.stringify(meetings_filtered, null, 2),
			'jitsi_meeting_report.json',
			'application/json'
		);
	}
</script>

<svelte:head>
	<title>&AElig;: Jitsi Meeting Reports</title>
</svelte:head>

<div class="p-4 space-y-4 w-full max-w-5xl">

	<!-- Page header + export buttons -->
	<div class="flex flex-row flex-wrap items-center justify-between gap-2">
		<h1 class="text-xl font-bold">Jitsi Meeting Reports</h1>
		<div class="flex gap-2">
			<button
				type="button"
				onclick={export_csv}
				disabled={meetings_filtered.length === 0}
				title="Export filtered meetings as CSV"
				class="btn btn-sm preset-tonal-primary disabled:opacity-40"
			>
				<span class="fas fa-file-csv" aria-hidden="true"></span>
				Export CSV
			</button>
			<button
				type="button"
				onclick={export_json}
				disabled={meetings_filtered.length === 0}
				title="Export filtered meetings as JSON"
				class="btn btn-sm preset-tonal-surface border border-surface-200-800 disabled:opacity-40"
			>
				<span class="fas fa-file-code" aria-hidden="true"></span>
				Export JSON
			</button>
		</div>
	</div>

	<!-- Filter bar -->
	<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-3 flex flex-row flex-wrap gap-3 items-end">
		<div>
			<label for="filter_min_p" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
				Min. Participants
			</label>
			<input
				type="number"
				id="filter_min_p"
				min="0"
				bind:value={filter_min_participants}
				class="border border-surface-200-800 rounded px-2 py-1 w-20 bg-surface-50-950"
			/>
		</div>
		<div>
			<label for="filter_room" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
				Room Name
			</label>
			<input
				type="text"
				id="filter_room"
				placeholder="Search rooms..."
				bind:value={filter_room_name}
				class="border border-surface-200-800 rounded px-2 py-1 bg-surface-50-950"
			/>
		</div>
		<div>
			<label for="filter_date_from" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
				From
			</label>
			<input
				type="date"
				id="filter_date_from"
				bind:value={filter_date_from}
				class="border border-surface-200-800 rounded px-2 py-1 bg-surface-50-950"
			/>
		</div>
		<div>
			<label for="filter_date_to" class="block text-xs uppercase tracking-wide opacity-40 mb-1">
				To
			</label>
			<input
				type="date"
				id="filter_date_to"
				bind:value={filter_date_to}
				class="border border-surface-200-800 rounded px-2 py-1 bg-surface-50-950"
			/>
		</div>
		{#if filters_are_modified}
			<button
				type="button"
				onclick={reset_filters}
				class="btn btn-sm preset-tonal-surface border border-surface-200-800 self-end"
				title="Reset all filters to defaults"
			>
				<span class="fas fa-times" aria-hidden="true"></span>
				Reset
			</button>
		{/if}
	</div>

	{#if meetings_loading}
		<!-- Loading skeleton -->
		<div class="space-y-2 animate-pulse" role="status" aria-live="polite" aria-label="Loading meeting reports">
			{#each [1, 2, 3, 4] as _, i (i)}
				<div class="h-14 w-full bg-surface-200-800 rounded-xl"></div>
			{/each}
		</div>

	{:else if meetings_error}
		<!-- Error state -->
		<div class="bg-error-100 border border-error-300 rounded-xl p-4">
			<div class="font-bold">Error Loading Reports</div>
			<p class="mt-1">An error occurred while fetching the meeting reports:</p>
			<pre class="mt-2 text-xs overflow-auto whitespace-pre-wrap">{meetings_error}</pre>
		</div>

	{:else}
		<!-- Summary stats -->
		{#if meetings_all.length > 0}
			<div class="grid grid-cols-2 sm:grid-cols-4 gap-2">
				<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-3 text-center">
					<div class="text-2xl font-bold">{summary.count}</div>
					<div class="text-xs uppercase tracking-wide opacity-40">Meetings Shown</div>
				</div>
				<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-3 text-center">
					<div class="text-2xl font-bold">{summary.total_participants}</div>
					<div class="text-xs uppercase tracking-wide opacity-40">Total Participants</div>
				</div>
				<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-3 text-center">
					<div class="text-2xl font-bold font-mono text-lg">{summary.avg_duration}</div>
					<div class="text-xs uppercase tracking-wide opacity-40">Avg Duration</div>
				</div>
				<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-3 text-center">
					<div class="text-2xl font-bold font-mono text-lg">{summary.total_duration}</div>
					<div class="text-xs uppercase tracking-wide opacity-40">Total Duration</div>
				</div>
			</div>
		{/if}

		<!-- Meeting list -->
		{#if meetings_filtered.length > 0}
			<div class="space-y-2">
				{#each meetings_filtered as meeting (meeting.meeting_id)}
					<div class="bg-surface-50-900 border border-surface-200-800 rounded-xl overflow-hidden">

						<!-- Accordion header -->
						<!-- svelte-ignore a11y_click_events_have_key_events -->
						<!-- svelte-ignore a11y_no_static_element_interactions -->
						<div
							class="p-3 cursor-pointer hover:bg-surface-100-900 transition-colors duration-200"
							onclick={() => toggle_accordion(meeting.meeting_id)}
						>
							<div class="flex items-center gap-2">
								<div class="flex-1 min-w-0">
									<div class="font-semibold truncate">{meeting.room_name}</div>
									<div class="text-sm opacity-60">{new Date(meeting.start_time).toLocaleString()}</div>
								</div>
								<div class="hidden sm:flex items-center gap-4 text-sm opacity-60 flex-none">
									<span title="Duration">
										<span class="fas fa-clock mr-1" aria-hidden="true"></span>
										{meeting.final_duration}
									</span>
									<span title="Participant count">
										<span class="fas fa-users mr-1" aria-hidden="true"></span>
										{meeting.final_participant_count}
									</span>
								</div>
								<div class="flex-none pl-2">
									<span
										class="fas transition-transform duration-200 inline-block"
										class:fa-chevron-down={!open_accordions[meeting.meeting_id]}
										class:fa-chevron-up={open_accordions[meeting.meeting_id]}
										aria-hidden="true"
									></span>
								</div>
							</div>
							<!-- Mobile stats row -->
							<div class="flex gap-4 text-sm opacity-60 mt-1 sm:hidden">
								<span><span class="fas fa-clock mr-1" aria-hidden="true"></span>{meeting.final_duration}</span>
								<span>
									<span class="fas fa-users mr-1" aria-hidden="true"></span>
									{meeting.final_participant_count}
									{meeting.final_participant_count === 1 ? 'participant' : 'participants'}
								</span>
							</div>
						</div>

						<!-- Accordion body -->
						{#if open_accordions[meeting.meeting_id]}
							<div class="border-t border-surface-200-800 p-4 grid grid-cols-1 md:grid-cols-2 gap-4">

								<!-- Event Timeline -->
								<div>
									<div class="text-xs uppercase tracking-wide opacity-40 mb-2">Event Timeline</div>
									{#if meeting.events && meeting.events.length > 0}
										<ul class="space-y-1">
											{#each meeting.events as event, i (i)}
												<li class="flex gap-2 items-start text-sm">
													<span class="font-mono text-xs opacity-60 whitespace-nowrap mt-0.5">
														[{new Date(event.timestamp).toLocaleTimeString()}]
													</span>
													<span>
														<span class="font-semibold">
															{ae_util.to_title_case(event.action.replace('jitsi_meeting_', ''))}
														</span>
														{#if event.details?.full_name}
															<span class="opacity-60"> — {event.details.full_name}</span>
														{/if}
													</span>
												</li>
											{/each}
										</ul>
									{:else}
										<p class="text-sm opacity-60 italic">No discrete events recorded.</p>
									{/if}
								</div>

								<!-- Final Participants -->
								<div>
									<div class="text-xs uppercase tracking-wide opacity-40 mb-2">
										Final Participants ({meeting.final_participant_count})
									</div>
									{#if meeting.final_participants && meeting.final_participants.length > 0}
										<table class="w-full text-sm">
											<thead>
												<tr class="border-b border-surface-200-800">
													<th class="text-left py-1 font-medium opacity-60">Name</th>
													<th class="text-left py-1 font-medium opacity-60">Role</th>
												</tr>
											</thead>
											<tbody>
												{#each meeting.final_participants as participant (participant.displayName)}
													<tr class="border-b border-surface-200-800 transition-colors duration-200 hover:bg-surface-100-900">
														<td class="py-1">{participant.displayName}</td>
														<td class="py-1">{ae_util.to_title_case(participant.role)}</td>
													</tr>
												{/each}
											</tbody>
										</table>
									{:else}
										<p class="text-sm opacity-60 italic">No participant data available.</p>
									{/if}
								</div>

							</div>
						{/if}
					</div>
				{/each}
			</div>

		{:else}
			<!-- Empty state -->
			<div class="bg-surface-100-900 border border-surface-200-800 rounded-xl p-6 text-center">
				{#if meetings_all.length > 0}
					<div class="font-semibold">No meetings match the current filters</div>
					<p class="text-sm opacity-60 mt-1">Try lowering the minimum participants or clearing the date range.</p>
					<button
						type="button"
						onclick={reset_filters}
						class="btn btn-sm preset-tonal-surface border border-surface-200-800 mt-3"
					>
						<span class="fas fa-times mr-1" aria-hidden="true"></span>
						Reset Filters
					</button>
				{:else}
					<div class="font-semibold">No Meeting Reports Found</div>
					<p class="text-sm opacity-60 mt-1">There are no Jitsi activity logs to display.</p>
				{/if}
			</div>
		{/if}

	{/if}

</div>
