{{ template "sync/layout/authenticated.html" . }}

{{ define "title" }}Review - Pools{{ end }}
{{ define "extraheader" }}
	<script
		type="text/javascript"
		src="//unpkg.com/maplibre-gl@5.0.1/dist/maplibre-gl.js"
	></script>
	<script src="/static/js/map-proxied-arcgis-tile.js"></script>
	<script src="/static/js/map-multipoint.js"></script>
	<script src="/static/js/time-relative.js"></script>
	<script>
		function formatAddress(a) {
			if (a == undefined) {
				return "undefined";
			}
			if (a.number == "" && a.street == "") {
				return "no address provided";
			}
			return a.number + " " + a.street + ", " + a.locality;
		}
		function reviewApp() {
			return {
				// State
				tasks: [],
				totalPending: 0,
				selectedTask: null,
				originalValues: {},
				loading: true,
				submitting: false,
				error: null,

				// Form fields for the selected task
				form: {
					condition: "",
					poolShape: "",
					poolLocation: {
						latitude: 0,
						longitude: 0,
					},
					ownerContact: "",
					residentContact: "",
				},

				// Computed: track which fields have changed
				get changes() {
					if (!this.selectedTask) return { updated: [], unchanged: [] };

					const updated = [];
					const unchanged = [];

					const fields = [
						{ key: "latitude", label: "Latitude" },
						{ key: "longitude", label: "Longitude" },
						{ key: "condition", label: "Pool condition" },
						{ key: "ownerContact", label: "Owner contact" },
						{ key: "residentContact", label: "Resident contact" },
						{ key: "poolShape", label: "Pool shape" },
					];

					fields.forEach((field) => {
						if (this.form[field.key] !== this.originalValues[field.key]) {
							updated.push(field.label);
						} else {
							unchanged.push(field.label);
						}
					});

					return { updated, unchanged };
				},

				// Initialize
				async init() {
					document.addEventListener("DOMContentLoaded", () => {
						const map = document.querySelector("map-multipoint");
						map.on("load", () => {
							map.addLayer({
								id: "parcel",
								minzoom: 14,
								paint: {
									"line-color": "#0f0",
								},
								source: "tegola",
								"source-layer": "parcel",
								type: "line",
							});
							map.addLayer({
								id: "pools",
								paint: {
									"circle-color": "#0D6EfD",
									"circle-radius": 7,
									"circle-stroke-width": 2,
									"circle-stroke-color": "#024AB6",
								},
								source: "tegola",
								"source-layer": "feature-pool",
								type: "circle",
							});
							// Create a popup, but don't add it to the map yet.
							const popup = new maplibregl.Popup({
								closeButton: false,
								closeOnClick: false,
							});
							// Make sure to detect marker change for overlapping markers
							// and use mousemove instead of mouseenter event
							let current_feature_coordinates = undefined;
							map.on("mousemove", "pools", (e) => {
								const feature_coordinates =
									e.features[0].geometry.coordinates.toString();
								if (current_feature_coordinates !== feature_coordinates) {
									current_feature_coordinates = feature_coordinates;

									// change the cursor style as a UI indicator
									map.getCanvas().style.cursor = "pointer";

									const coordinates =
										e.features[0].geometry.coordinates.slice();
									const condition = e.features[0].properties.condition;

									// Ensure that if the map is zoomed way out so we have multiple
									// copies from the globe wrapping that the popup appears over
									// they copy we are actually hovering over
									while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
										coordinates[0] +=
											e.lngLat.lng > coordinates[0] ? 360 : -360;
									}
									// Populate the popup, set its coordinates
									popup
										.setLngLat(coordinates)
										.setHTML(condition)
										.addTo(map._map);
								}
							});
							map.on("mouseleave", "pools", () => {
								current_feature_coordinates = undefined;
								map.getCanvas().style.cursor = "";
								popup.remove();
							});
						});
						const map_tile = document.querySelector("map-proxied-arcgis-tile");
						map_tile.on("load", () => {
							map_tile.addLayer({
								id: "parcel",
								minzoom: 14,
								paint: {
									"line-color": "#0f0",
								},
								source: "tegola",
								"source-layer": "parcel",
								type: "line",
							});
							map_tile.addLayer({
								id: "pools",
								paint: {
									"circle-color": "#0D6EfD",
									"circle-radius": 7,
									"circle-stroke-width": 2,
									"circle-stroke-color": "#024AB6",
								},
								source: "tegola",
								"source-layer": "feature-pool",
								type: "circle",
							});
						});
					});
					await this.fetchTasks();
				},

				// Fetch tasks from API
				async fetchTasks() {
					this.loading = true;
					this.error = null;

					try {
						const response = await fetch("/api/review-task/pool");
						if (!response.ok) {
							throw new Error("Failed to fetch tasks");
						}

						const data = await response.json();
						this.tasks = data.tasks || [];
						this.totalPending = data.total || this.tasks.length;

						// Auto-select first task if available
						if (this.tasks.length > 0 && !this.selectedTask) {
							this.selectTask(this.tasks[0]);
						}
					} catch (err) {
						this.error = err.message;
						console.error("Error fetching tasks:", err);
					} finally {
						this.loading = false;
						console.log("set loading", this.loading);
					}
				},

				// Select a task
				selectTask(task) {
					console.log("Selected task", task);
					this.selectedTask = task;

					// Populate form with task values
					this.form = {
						latitude: task.location.latitude,
						longitude: task.location.longitude,
						condition: task.condition || "",
						ownerContact: task.ownerContact || "",
						residentContact: task.residentContact || "",
						poolShape: task.poolShape || "",
					};

					// Store original values for change tracking
					this.originalValues = { ...this.form };

					// Update map and aerial image
					this.updateMap(task);
				},

				// Stub: Update map display
				updateMap(task) {
					console.log("Updating map for task:", task.id);
					const map = document.querySelector("map-multipoint");
					const loc = this.selectedTask.location;
					let markers = [
						new maplibregl.Marker({
							color: "#FF0000",
							draggable: false,
						}).setLngLat([loc.longitude, loc.latitude]),
					];
					map.SetMarkers(markers);

					const bounds = new maplibregl.LngLatBounds(
						new maplibregl.LngLat(loc.longitude - 0.005, loc.latitude - 0.005),
						new maplibregl.LngLat(loc.longitude + 0.005, loc.latitude + 0.005),
					);

					map.FitBounds(bounds, {
						padding: 50,
					});
				},

				// Format relative time
				formatRelativeTime(dateString) {
					if (!dateString) return "";

					const date = new Date(dateString);
					const now = new Date();
					const diffMs = now - date;
					const diffMins = Math.floor(diffMs / 60000);
					const diffHours = Math.floor(diffMins / 60);
					const diffDays = Math.floor(diffHours / 24);

					if (diffMins < 1) return "just now";
					if (diffMins < 60) return `${diffMins} min ago`;
					if (diffHours < 24)
						return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
					return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
				},

				// Submit review action
				async submitReview(action) {
					if (!this.selectedTask || this.submitting) return;

					this.submitting = true;
					this.error = null;

					try {
						const payload = {
							task_id: this.selectedTask.id,
							status: action, // 'committed' or 'discarded'
							updates: {},
						};

						// Include changed fields in the payload
						if (action === "committed") {
							Object.keys(this.form).forEach((key) => {
								if (this.form[key] !== this.originalValues[key]) {
									payload.updates[key] = this.form[key];
								}
							});
						}

						const response = await fetch(`/api/review/pool`, {
							method: "POST",
							headers: {
								"Content-Type": "application/json",
							},
							body: JSON.stringify(payload),
						});

						if (!response.ok) {
							throw new Error("Failed to submit review");
						}

						// Remove task from list
						const taskIndex = this.tasks.findIndex(
							(t) => t.id === this.selectedTask.id,
						);
						if (taskIndex > -1) {
							this.tasks.splice(taskIndex, 1);
							this.totalPending = Math.max(0, this.totalPending - 1);
						}

						// Select next task or clear selection
						if (this.tasks.length > 0) {
							const nextIndex = Math.min(taskIndex, this.tasks.length - 1);
							this.selectTask(this.tasks[nextIndex]);
						} else {
							this.selectedTask = null;
							this.form = {
								condition: "",
								ownerContact: "",
								residentContact: "",
								poolShape: "",
							};
							this.originalValues = {};
						}
						// Update list of tasks
						this.fetchTasks();
					} catch (err) {
						this.error = err.message;
						console.error("Error submitting review:", err);
					} finally {
						this.submitting = false;
					}
				},

				// Mark as committed
				markReviewed() {
					this.submitReview("committed");
				},

				// Discard entry
				discardEntry() {
					this.submitReview("discarded");
				},
				updatePoolLocation(e, pool_id) {
					console.log("map click", pool_id, e.detail);
					const map = e.detail.map;
					const loc = {
						latitude: e.detail.lat,
						longitude: e.detail.lng,
					};
					map.SetMarkers([
						new maplibregl.Marker({
							color: "#FF0000",
							draggable: false,
						}).setLngLat([e.detail.lng, e.detail.lat]),
					]);
					this.form.latitude = e.detail.lat;
					this.form.longitude = e.detail.lng;
				},
			};
		}
	</script>
	<style>
		body {
			background-color: #f5f5f5;
		}
		.left-panel {
			background-color: white;
			height: 100vh;
			overflow-y: auto;
			border-right: 1px solid #dee2e6;
		}
		.middle-panel {
			background-color: white;
			height: 100vh;
			overflow-y: auto;
			padding: 20px;
		}
		.right-panel {
			background-color: white;
			height: 100vh;
			overflow-y: auto;
			border-left: 1px solid #dee2e6;
			padding: 20px;
		}
		.entry-item {
			padding: 15px;
			border-bottom: 1px solid #e9ecef;
			cursor: pointer;
			transition: background-color 0.2s;
		}
		.entry-item:hover {
			background-color: #f8f9fa;
		}
		.entry-item.active {
			background-color: #e7f3ff;
			border-left: 4px solid #0d6efd;
		}
		.placeholder-box {
			background-color: #e9ecef;
			border: 2px dashed #adb5bd;
			display: flex;
			align-items: center;
			justify-content: center;
			color: #6c757d;
			font-size: 18px;
			margin-bottom: 20px;
		}
		.map-placeholder {
			height: 300px;
		}
		.image-placeholder {
			height: 400px;
		}
		.action-btn {
			width: 100%;
			margin-bottom: 10px;
			padding: 12px;
			font-size: 16px;
		}
		.status-badge {
			font-size: 11px;
		}
	</style>
{{ end }}
{{ define "content" }}
	<div class="container-fluid" x-data="reviewApp()">
		<div class="row">
			<!-- Left Column - Entry List -->
			<div class="col-md-3 p-0 left-panel">
				<!-- Error Alert -->
				<div x-show="error" class="mt-3">
					<span x-text="error"></span>
					<button
						type="button"
						class="btn-close"
						@click="error = null"
					></button>
				</div>

				<div class="p-3 border-bottom bg-primary text-white">
					<h5 class="mb-0"><i class="bi bi-list-ul"></i> Review Queue</h5>
					<small><span x-text="totalPending"></span> entries pending</small>
				</div>

				<!-- Empty State -->
				<div
					x-show="!loading && tasks.length === 0"
					class="p-4 text-center text-muted"
				>
					<i class="bi bi-check-circle" style="font-size: 48px;"></i>
					<p class="mt-2">No entries to review!</p>
				</div>

				<!-- Task List -->
				<template x-for="task in tasks" :key="task.id">
					<div
						class="entry-item"
						:class="{ 'active': selectedTask && selectedTask.id === task.id }"
						@click="selectTask(task)"
					>
						<div class="d-flex justify-content-between align-items-start">
							<div>
								<i class="bi bi-droplet"></i>
								<strong>Pool <span x-text="task.id"></span></strong>
							</div>
							<small class="text-muted" x-text="task.condition"></small>
						</div>
						<small
							class="text-muted d-block mt-1"
							x-text="formatAddress(task.address)"
						></small>
					</div>
				</template>
			</div>

			<!-- Middle Column - Details and Media -->
			<div class="col-md-6 p-0 middle-panel">
				<!-- No Selection State -->
				<template x-show="selectedTask == null">
					<div
						class="h-100 d-flex align-items-center justify-content-center text-muted"
					>
						<div class="text-center">
							<i class="bi bi-cursor-fill" style="font-size: 48px;"></i>
							<p class="mt-2">Select an entry from the list to review</p>
						</div>
					</div>
				</template>

				<!-- Selected Task Details -->
				<div x-show="selectedTask">
					<div class="mb-4">
						<h4 class="mb-3">
							Entry #<span x-text="selectedTask?.id"></span> Details
						</h4>

						<form @submit.prevent>
							<div class="row mb-3">
								<label class="col-sm-3 col-form-label fw-bold">Address:</label>
								<div class="col-sm-9">
									<input
										type="text"
										class="form-control"
										:value="formatAddress(selectedTask?.address)"
										readonly
									/>
								</div>
							</div>

							<div class="row mb-3">
								<label class="col-sm-3 col-form-label fw-bold"
									>Longitude:</label
								>
								<div class="col-sm-9">
									<input
										type="text"
										class="form-control"
										x-model="form.longitude"
										:class="{ 'border-warning': form.longitude !== originalValues.longitude }"
									/>
								</div>
							</div>
							<div class="row mb-3">
								<label class="col-sm-3 col-form-label fw-bold">Latitude:</label>
								<div class="col-sm-9">
									<input
										type="text"
										class="form-control"
										x-model="form.latitude"
										:class="{ 'border-warning': form.latitude !== originalValues.latitude }"
									/>
								</div>
							</div>
							<div class="row mb-3">
								<label class="col-sm-3 col-form-label fw-bold"
									>Pool Condition:</label
								>
								<div class="col-sm-9">
									<select
										class="form-select"
										x-model="form.condition"
										:class="{ 'border-warning': form.condition !== originalValues.condition }"
									>
										<option value="">-- Select --</option>
										<option value="blue">Blue</option>
										<option value="dry">Dry</option>
										<option value="false pool">False Pool</option>
										<option value="unknown">Unknown</option>
										<option value="green">Green</option>
										<option value="murky">Murky</option>
									</select>
								</div>
							</div>

							<template x-if="form.ownerContact != ''">
								<div class="row mb-3">
									<label class="col-sm-3 col-form-label fw-bold"
										>Owner Contact:</label
									>
									<div class="col-sm-9">
										<input
											type="text"
											class="form-control"
											x-model="form.ownerContact"
											:class="{ 'border-warning': form.ownerContact !== originalValues.ownerContact }"
										/>
									</div>
								</div>
							</template>

							<template x-if="form.residentContact != ''">
								<div class="row mb-4">
									<label class="col-sm-3 col-form-label fw-bold"
										>Resident Contact:</label
									>
									<div class="col-sm-9">
										<input
											type="text"
											class="form-control"
											x-model="form.residentContact"
											:class="{ 'border-warning': form.residentContact !== originalValues.residentContact }"
										/>
									</div>
								</div>
							</template>
						</form>
					</div>

					<!-- Map Placeholder -->
					<div class="map-container">
						<map-multipoint
							id="map"
							organization-id="{{ .Organization.ID }}"
							tegola="{{ .URL.Tegola }}"
							xmin="{{ .Organization.ServiceArea.Min.X }}"
							ymin="{{ .Organization.ServiceArea.Min.Y }}"
							xmax="{{ .Organization.ServiceArea.Max.X }}"
							ymax="{{ .Organization.ServiceArea.Max.Y }}"
						></map-multipoint>
					</div>

					<div class="map-container">
						<map-proxied-arcgis-tile
							class="map"
							organization-id="{{ .Organization.ID }}"
							tegola="{{ .URL.Tegola }}"
							{{ .C.URLTiles }}
							@map-click="updatePoolLocation($event, selectedTask.id)"
							:latitude="selectedTask?.location.latitude ?? 0"
							:longitude="selectedTask?.location.longitude ?? 0"
						>
						</map-proxied-arcgis-tile>
					</div>
				</div>
			</div>

			<!-- Right Column - Actions -->
			<div class="col-md-3 p-0 right-panel">
				<h5 class="mb-4">Actions</h5>

				<button
					class="btn btn-success action-btn"
					@click="markReviewed()"
					:disabled="!selectedTask || submitting"
				>
					<span x-show="!submitting">
						<i class="bi bi-check-circle"></i> Complete Review
					</span>
					<span x-show="submitting">
						<span class="spinner-border spinner-border-sm" role="status"></span>
						Submitting...
					</span>
				</button>

				<div class="card mt-3" x-show="selectedTask">
					<div class="card-body" x-show="changes.updated.length > 0">
						<h6 class="card-title">
							<i class="bi bi-pencil-square text-warning"></i> Updates
						</h6>
						<ul class="mb-0">
							<template x-for="item in changes.updated" :key="item">
								<li x-text="item"></li>
							</template>
						</ul>
					</div>
					<div class="card-body" x-show="changes.unchanged.length > 0">
						<h6 class="card-title">
							<i class="bi bi-dash-circle text-muted"></i> Not changed
						</h6>
						<ul class="mb-0">
							<template x-for="item in changes.unchanged" :key="item">
								<li x-text="item"></li>
							</template>
						</ul>
					</div>
				</div>

				<button
					class="btn btn-danger action-btn"
					@click="discardEntry()"
					:disabled="!selectedTask || submitting"
				>
					<i class="bi bi-trash"></i> Discard Entry
				</button>

				<!-- Keyboard Shortcuts Help -->
				<div class="card mt-3">
					<div class="card-body">
						<h6 class="card-title"><i class="bi bi-keyboard"></i> Tips</h6>
						<small class="text-muted">
							Fields with a yellow border have been modified from their original
							values.
						</small>
					</div>
				</div>
			</div>
		</div>
	</div>
{{ end }}
