/**
 * <map-import-modal> — Google Maps GeoJSON import modal for rMaps.
 * Dispatches 'import-places' CustomEvent with { places: { name, lat, lng }[] } detail.
 * Dispatches 'modal-close' on dismiss.
 */

import { parseGoogleMapsGeoJSON } from "./map-import";

class MapImportModal extends HTMLElement {
	private _step: "upload" | "preview" | "done" = "upload";
	private _places: { name: string; lat: number; lng: number; selected: boolean }[] = [];

	connectedCallback() { this.render(); }

	private esc(s: string): string { const d = document.createElement("div"); d.textContent = s || ""; return d.innerHTML; }

	private close() {
		this.dispatchEvent(new CustomEvent("modal-close", { bubbles: true, composed: true }));
		this.remove();
	}

	/** Extract GeoJSON from a Google Takeout ZIP (or any ZIP containing .json/.geojson files) */
	private async handleZip(file: File): Promise<string | null> {
		const JSZip = (await import("jszip")).default;
		const zip = await JSZip.loadAsync(file);

		// Google Takeout known paths (in order of preference)
		const takeoutPaths = [
			"Takeout/Maps/My labeled places/Labeled places.json",
			"Takeout/Maps (My Places)/Saved Places.json",
			"Takeout/Maps/Saved Places.json",
		];
		for (const p of takeoutPaths) {
			const entry = zip.file(p);
			if (entry) return entry.async("string");
		}

		// Fallback: find any .json or .geojson containing a FeatureCollection
		const jsonFiles = zip.file(/\.(json|geojson)$/i);
		for (const f of jsonFiles) {
			const text = await f.async("string");
			try {
				const parsed = JSON.parse(text);
				if (parsed?.type === "FeatureCollection") return text;
			} catch { /* not valid JSON, skip */ }
		}

		return null;
	}

	private render() {
		this.style.cssText = `position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.6);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);`;

		if (this._step === "upload") this.renderUpload();
		else if (this._step === "preview") this.renderPreview();
		else this.renderDone();

		// Shared close
		this.querySelector("#i-close")?.addEventListener("click", () => this.close());
		this.addEventListener("click", (e) => { if (e.target === this) this.close(); });
	}

	private renderUpload() {
		this.innerHTML = `
			<div style="background:var(--rs-bg-surface);border:1px solid var(--rs-border-strong);border-radius:14px;padding:24px;max-width:420px;width:90%;">
				<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
					<div style="font-size:16px;font-weight:600;color:var(--rs-text-primary);">\u{1F4E5} Import Places</div>
					<button id="i-close" style="background:none;border:none;color:var(--rs-text-muted);cursor:pointer;font-size:18px;">\u2715</button>
				</div>
				<div id="i-drop" style="border:2px dashed var(--rs-border);border-radius:10px;padding:40px;text-align:center;cursor:pointer;transition:border-color 0.2s;">
					<div style="font-size:28px;margin-bottom:8px;">\u{1F4C2}</div>
					<div style="font-size:13px;color:var(--rs-text-secondary);margin-bottom:4px;">Drop a GeoJSON or Google Takeout ZIP here</div>
					<div style="font-size:11px;color:var(--rs-text-muted);">or click to browse (.json, .geojson, .zip)</div>
					<input type="file" id="i-file" accept=".json,.geojson,.zip" style="display:none;">
				</div>
				<div id="i-err" style="display:none;margin-top:12px;font-size:12px;color:#ef4444;padding:8px;border-radius:6px;background:rgba(239,68,68,0.1);"></div>
			</div>
		`;

		const processJson = (jsonStr: string) => {
			const result = parseGoogleMapsGeoJSON(jsonStr);
			if (!result.success) {
				const err = this.querySelector("#i-err") as HTMLElement;
				err.style.display = "block"; err.textContent = result.error || "No places found"; return;
			}
			this._places = result.places.map(p => ({ ...p, selected: true }));
			this._step = "preview";
			this.render();
		};

		const handleFile = (file: File) => {
			if (file.size > 50 * 1024 * 1024) {
				const err = this.querySelector("#i-err") as HTMLElement;
				err.style.display = "block"; err.textContent = "File too large (max 50 MB)"; return;
			}

			if (file.name.endsWith(".zip") || file.type === "application/zip") {
				this.handleZip(file).then((jsonStr) => {
					if (!jsonStr) {
						const err = this.querySelector("#i-err") as HTMLElement;
						err.style.display = "block"; err.textContent = "No GeoJSON FeatureCollection found in ZIP"; return;
					}
					processJson(jsonStr);
				}).catch(() => {
					const err = this.querySelector("#i-err") as HTMLElement;
					err.style.display = "block"; err.textContent = "Failed to read ZIP file";
				});
				return;
			}

			const reader = new FileReader();
			reader.onload = () => processJson(reader.result as string);
			reader.readAsText(file);
		};

		const drop = this.querySelector("#i-drop")!;
		const fileInput = this.querySelector("#i-file") as HTMLInputElement;
		drop.addEventListener("click", () => fileInput.click());
		drop.addEventListener("dragover", (e) => { e.preventDefault(); (drop as HTMLElement).style.borderColor = "#4f46e5"; });
		drop.addEventListener("dragleave", () => { (drop as HTMLElement).style.borderColor = "var(--rs-border)"; });
		drop.addEventListener("drop", (e) => {
			e.preventDefault(); (drop as HTMLElement).style.borderColor = "var(--rs-border)";
			const file = (e as DragEvent).dataTransfer?.files[0];
			if (file) handleFile(file);
		});
		fileInput.addEventListener("change", () => { if (fileInput.files?.[0]) handleFile(fileInput.files[0]); });
	}

	private renderPreview() {
		const count = this._places.filter(p => p.selected).length;
		this.innerHTML = `
			<div style="background:var(--rs-bg-surface);border:1px solid var(--rs-border-strong);border-radius:14px;padding:24px;max-width:420px;width:90%;max-height:80vh;overflow-y:auto;">
				<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
					<div style="font-size:16px;font-weight:600;color:var(--rs-text-primary);">Preview (${this._places.length} places)</div>
					<div style="display:flex;gap:6px;align-items:center;">
						<button id="i-toggle-all" style="padding:4px 10px;border-radius:6px;border:1px solid var(--rs-border);background:var(--rs-input-bg);color:var(--rs-text-secondary);cursor:pointer;font-size:11px;">${count === this._places.length ? "Deselect all" : "Select all"}</button>
						<button id="i-close" style="background:none;border:none;color:var(--rs-text-muted);cursor:pointer;font-size:18px;">\u2715</button>
					</div>
				</div>
				<div style="margin-bottom:12px;">
					${this._places.map((p, i) => `
						<label style="display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--rs-border);cursor:pointer;font-size:12px;color:var(--rs-text-secondary);">
							<input type="checkbox" data-idx="${i}" ${p.selected ? "checked" : ""} style="accent-color:#4f46e5;">
							<div style="flex:1;min-width:0;">
								<div style="font-weight:600;color:var(--rs-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${this.esc(p.name)}</div>
								<div style="font-size:10px;color:var(--rs-text-muted);">${p.lat.toFixed(4)}, ${p.lng.toFixed(4)}</div>
							</div>
						</label>
					`).join("")}
				</div>
				<button id="i-confirm" style="width:100%;padding:10px;border-radius:8px;border:none;background:#4f46e5;color:#fff;font-weight:600;cursor:pointer;font-size:13px;">Import ${count} Places as Waypoints</button>
			</div>
		`;

		this.querySelectorAll("[data-idx]").forEach(cb => {
			cb.addEventListener("change", (e) => {
				this._places[parseInt((cb as HTMLElement).dataset.idx!, 10)].selected = (e.target as HTMLInputElement).checked;
				const btn = this.querySelector("#i-confirm");
				if (btn) btn.textContent = `Import ${this._places.filter(p => p.selected).length} Places as Waypoints`;
			});
		});

		this.querySelector("#i-toggle-all")?.addEventListener("click", () => {
			const allSelected = this._places.every(p => p.selected);
			this._places.forEach(p => p.selected = !allSelected);
			this._step = "preview";
			this.render();
		});

		this.querySelector("#i-confirm")?.addEventListener("click", () => {
			const selected = this._places.filter(p => p.selected).map(({ name, lat, lng }) => ({ name, lat, lng }));
			this.dispatchEvent(new CustomEvent("import-places", { detail: { places: selected }, bubbles: true, composed: true }));
			this._step = "done";
			this.render();
		});
	}

	private renderDone() {
		const count = this._places.filter(p => p.selected).length;
		this.innerHTML = `
			<div style="background:var(--rs-bg-surface);border:1px solid var(--rs-border-strong);border-radius:14px;padding:24px;max-width:360px;width:90%;text-align:center;">
				<div style="font-size:32px;margin-bottom:8px;">\u2705</div>
				<div style="font-size:16px;font-weight:600;color:var(--rs-text-primary);margin-bottom:8px;">Imported ${count} places!</div>
				<div style="font-size:12px;color:var(--rs-text-muted);margin-bottom:16px;">They've been added as waypoints to this room.</div>
				<button id="i-done" style="padding:10px 24px;border-radius:8px;border:none;background:#4f46e5;color:#fff;font-weight:600;cursor:pointer;font-size:13px;">Done</button>
			</div>
		`;
		this.querySelector("#i-done")?.addEventListener("click", () => this.close());
	}
}

customElements.define("map-import-modal", MapImportModal);
export { MapImportModal };
