/**
 * <folk-bnb-view> — Main rBnb module view.
 *
 * Layout: Search/filter bar, listing grid with map toggle (Leaflet),
 * host dashboard (my listings + incoming requests), stay request sidebar.
 */

import { LightTourEngine } from '../../../shared/tour-engine';
import type { TourStep } from '../../../shared/tour-engine';
import './folk-listing';
import './folk-stay-request';
import { startPresenceHeartbeat } from '../../../shared/collab-presence';
import { getModuleApiBase } from "../../../shared/url-helpers";
import type { DocumentId } from "../../../shared/local-first/document";
import { bnbSchema, bnbDocId } from "../schemas";
import { ViewHistory } from "../../../shared/view-history.js";

const BNB_TOUR_STEPS: TourStep[] = [
	{ target: '.bnb-search', title: 'Search', message: 'Filter listings by location, type, or economy model.' },
	{ target: '#bnb-content', title: 'Browse Stays', message: 'Tap a listing card to see details and stay requests.' },
	{ target: '.bnb-view__toggle[data-view="map"]', title: 'Map View', message: 'See all listings on an interactive map.' },
];

// ── Leaflet CDN Loader ──

let _leafletReady = false;
let _leafletPromise: Promise<void> | null = null;

function ensureLeaflet(): Promise<void> {
	if (_leafletReady && typeof (window as any).L !== 'undefined') return Promise.resolve();
	if (_leafletPromise) return _leafletPromise;
	_leafletPromise = new Promise<void>((resolve, reject) => {
		const s = document.createElement('script');
		s.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
		s.onload = () => { _leafletReady = true; resolve(); };
		s.onerror = () => reject(new Error('Leaflet load failed'));
		document.head.appendChild(s);
	});
	return _leafletPromise;
}

// ── Economy badges ──

const ECONOMY_BADGE: Record<string, { icon: string; label: string; cls: string }> = {
	gift:          { icon: '\u{1F49A}', label: 'Gift',          cls: 'bnb-badge--gift' },
	exchange:      { icon: '\u{1F91D}', label: 'Exchange',      cls: 'bnb-badge--exchange' },
	sliding_scale: { icon: '\u{2696}',  label: 'Sliding Scale', cls: 'bnb-badge--sliding_scale' },
	suggested:     { icon: '\u{1F4AD}', label: 'Suggested',     cls: 'bnb-badge--suggested' },
	fixed:         { icon: '\u{1F3F7}', label: 'Fixed',         cls: 'bnb-badge--fixed' },
};

const TYPE_ICONS: Record<string, string> = {
	couch: '\u{1F6CB}', room: '\u{1F6CF}', apartment: '\u{1F3E2}', cabin: '\u{1F3E1}',
	tent_site: '\u{26FA}', land: '\u{1F333}', studio: '\u{1F3A8}', loft: '\u{1F3D7}',
	house: '\u{1F3E0}', other: '\u{1F3E8}',
};

class FolkBnbView extends HTMLElement {
	static observedAttributes = ['space'];

	#space = 'demo';
	#listings: any[] = [];
	#stays: any[] = [];
	#stats: any = null;
	#selectedStay: any = null;
	#view: 'grid' | 'map' = 'grid';
	private _history = new ViewHistory<'grid' | 'map'>('grid', 'rbnb');
	#search = '';
	#typeFilter = '';
	#economyFilter = '';
	#map: any = null;
	#mapContainer: HTMLElement | null = null;
	#tour: LightTourEngine | null = null;
	private _stopPresence: (() => void) | null = null;
	private _offlineUnsub: (() => void) | null = null;
	private _subscribedDocIds: string[] = [];

	connectedCallback() {
		this.#space = this.getAttribute('space') || 'demo';
		this.#render();
		this.#loadData();
		this._stopPresence = startPresenceHeartbeat(() => ({ module: 'rbnb', context: 'Listings' }));
		if (this.#space !== 'demo') this.subscribeOffline();
		window.addEventListener('rspace-view-restored', this._onViewRestored as EventListener);
	}

	disconnectedCallback() {
		this._history.destroy();
		window.removeEventListener('rspace-view-restored', this._onViewRestored as EventListener);
		this._stopPresence?.();
		this._offlineUnsub?.(); this._offlineUnsub = null;
		const runtime = (window as any).__rspaceOfflineRuntime;
		if (runtime) {
			for (const id of this._subscribedDocIds) runtime.unsubscribe(id);
		}
		this._subscribedDocIds = [];
	}

	private _onViewRestored = (e: CustomEvent) => {
		if (e.detail?.moduleId !== 'rbnb') return;
		this.#view = e.detail.view;
		this.#render();
		this.#renderContent();
	};

	private async subscribeOffline() {
		const runtime = (window as any).__rspaceOfflineRuntime;
		if (!runtime?.isInitialized) return;
		try {
			const docId = bnbDocId(this.#space) as DocumentId;
			await runtime.subscribe(docId, bnbSchema);
			this._subscribedDocIds.push(docId);
		} catch { /* runtime unavailable */ }
	}

	attributeChangedCallback(name: string, _old: string, val: string) {
		if (name === 'space') {
			this.#space = val || 'demo';
			this.#loadData();
		}
	}

	async #loadData() {
		try {
			const [listingsRes, staysRes, statsRes] = await Promise.all([
				fetch(`${getModuleApiBase("rbnb")}/api/listings`),
				fetch(`${getModuleApiBase("rbnb")}/api/stays`),
				fetch(`${getModuleApiBase("rbnb")}/api/stats`),
			]);

			if (listingsRes.ok) {
				const data = await listingsRes.json();
				this.#listings = data.results || [];
			}
			if (staysRes.ok) {
				const data = await staysRes.json();
				this.#stays = data.results || [];
			}
			if (statsRes.ok) {
				this.#stats = await statsRes.json();
			}

			this.#renderContent();
		} catch (err) {
			console.warn('[rBnb] Failed to load data:', err);
		}
	}

	get #filteredListings() {
		let list = this.#listings;

		if (this.#search) {
			const term = this.#search.toLowerCase();
			list = list.filter((l: any) =>
				l.title.toLowerCase().includes(term) ||
				l.description?.toLowerCase().includes(term) ||
				l.location_name?.toLowerCase().includes(term) ||
				l.host_name?.toLowerCase().includes(term)
			);
		}
		if (this.#typeFilter) list = list.filter((l: any) => l.type === this.#typeFilter);
		if (this.#economyFilter) list = list.filter((l: any) => l.economy === this.#economyFilter);

		return list;
	}

	#render() {
		this.innerHTML = `
			<div class="bnb-view">
				<div class="bnb-view__header" style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem">
					<h2 style="margin:0;font-size:1.25rem;color:var(--rs-text,#e2e8f0);display:flex;align-items:center;gap:0.5rem">
						\u{1F3E0} Community Hospitality
						${this.#stats ? `<span style="font-size:0.75rem;color:var(--rs-text-muted,#94a3b8);font-weight:400">${this.#stats.active_listings || 0} listings</span>` : ''}
					</h2>
					<div style="display:flex;gap:0.5rem">
						<button class="bnb-view__toggle" data-view="grid" style="padding:0.4rem 0.75rem;border-radius:0.375rem;border:1px solid var(--rs-border,#334155);background:${this.#view === 'grid' ? 'rgba(245,158,11,0.15)' : 'transparent'};color:var(--rs-text,#e2e8f0);cursor:pointer;font-size:0.82rem">
							\u{25A6} Grid
						</button>
						<button class="bnb-view__toggle" data-view="map" style="padding:0.4rem 0.75rem;border-radius:0.375rem;border:1px solid var(--rs-border,#334155);background:${this.#view === 'map' ? 'rgba(245,158,11,0.15)' : 'transparent'};color:var(--rs-text,#e2e8f0);cursor:pointer;font-size:0.82rem">
							\u{1F5FA} Map
						</button>
						<button id="btn-tour" style="padding:0.4rem 0.75rem;border-radius:0.375rem;border:1px solid var(--rs-border,#334155);background:transparent;color:var(--rs-text-muted,#94a3b8);cursor:pointer;font-size:0.78rem">Tour</button>
					</div>
				</div>

				<div class="bnb-search">
					<input class="bnb-search__input" type="text" placeholder="Search listings..." value="${this.#esc(this.#search)}">
					<select class="bnb-search__select" id="type-filter">
						<option value="">All Types</option>
						<option value="couch" ${this.#typeFilter === 'couch' ? 'selected' : ''}>Couch</option>
						<option value="room" ${this.#typeFilter === 'room' ? 'selected' : ''}>Room</option>
						<option value="cabin" ${this.#typeFilter === 'cabin' ? 'selected' : ''}>Cabin</option>
						<option value="tent_site" ${this.#typeFilter === 'tent_site' ? 'selected' : ''}>Tent Site</option>
						<option value="loft" ${this.#typeFilter === 'loft' ? 'selected' : ''}>Loft</option>
						<option value="house" ${this.#typeFilter === 'house' ? 'selected' : ''}>House</option>
						<option value="land" ${this.#typeFilter === 'land' ? 'selected' : ''}>Land</option>
						<option value="apartment" ${this.#typeFilter === 'apartment' ? 'selected' : ''}>Apartment</option>
						<option value="studio" ${this.#typeFilter === 'studio' ? 'selected' : ''}>Studio</option>
					</select>
					<select class="bnb-search__select" id="economy-filter">
						<option value="">All Economies</option>
						<option value="gift" ${this.#economyFilter === 'gift' ? 'selected' : ''}>\u{1F49A} Gift</option>
						<option value="exchange" ${this.#economyFilter === 'exchange' ? 'selected' : ''}>\u{1F91D} Exchange</option>
						<option value="sliding_scale" ${this.#economyFilter === 'sliding_scale' ? 'selected' : ''}>\u{2696} Sliding Scale</option>
						<option value="suggested" ${this.#economyFilter === 'suggested' ? 'selected' : ''}>\u{1F4AD} Suggested</option>
						<option value="fixed" ${this.#economyFilter === 'fixed' ? 'selected' : ''}>\u{1F3F7} Fixed</option>
					</select>
				</div>

				<div class="bnb-view__content" id="bnb-content"></div>

				<div class="bnb-view__sidebar" id="bnb-sidebar" style="display:none;position:fixed;top:0;right:0;width:420px;height:100vh;background:var(--rs-bg,#0f172a);border-left:1px solid var(--rs-border,#334155);z-index:100;overflow-y:auto;padding:1rem">
					<button id="close-sidebar" style="position:absolute;top:0.75rem;right:0.75rem;background:none;border:none;color:var(--rs-text-muted,#94a3b8);font-size:1.25rem;cursor:pointer">\u{2715}</button>
					<div id="sidebar-content"></div>
				</div>
			</div>
		`;

		this.#wireEvents();

		// Tour
		this.#tour = new LightTourEngine(this.querySelector('.bnb-view') as HTMLElement || this, BNB_TOUR_STEPS, 'rbnb_tour_done');
		if (!localStorage.getItem('rbnb_tour_done')) {
			setTimeout(() => this.#tour?.start(), 800);
		}
		this.querySelector('#btn-tour')?.addEventListener('click', () => this.#tour?.start());
	}

	#wireEvents() {
		// Search input
		const searchInput = this.querySelector('.bnb-search__input') as HTMLInputElement;
		searchInput?.addEventListener('input', (e) => {
			this.#search = (e.target as HTMLInputElement).value;
			this.#renderContent();
		});

		// Type filter
		this.querySelector('#type-filter')?.addEventListener('change', (e) => {
			this.#typeFilter = (e.target as HTMLSelectElement).value;
			this.#renderContent();
		});

		// Economy filter
		this.querySelector('#economy-filter')?.addEventListener('change', (e) => {
			this.#economyFilter = (e.target as HTMLSelectElement).value;
			this.#renderContent();
		});

		// View toggles
		for (const btn of this.querySelectorAll('.bnb-view__toggle')) {
			btn.addEventListener('click', () => {
				const v = (btn as HTMLElement).dataset.view as 'grid' | 'map';
				this._history.push(v);
				this.#view = v;
				this.#render();
				this.#renderContent();
			});
		}

		// Close sidebar
		this.querySelector('#close-sidebar')?.addEventListener('click', () => {
			this.#closeSidebar();
		});

		// Stay action events (bubbled from folk-stay-request)
		this.addEventListener('stay-action', ((e: CustomEvent) => {
			this.#handleStayAction(e.detail.stayId, e.detail.action);
		}) as EventListener);

		this.addEventListener('stay-message', ((e: CustomEvent) => {
			this.#handleStayMessage(e.detail.stayId, e.detail.body);
		}) as EventListener);
	}

	#renderContent() {
		const container = this.querySelector('#bnb-content');
		if (!container) return;

		const listings = this.#filteredListings;

		if (this.#view === 'map') {
			container.innerHTML = `<div id="bnb-map" style="width:100%;height:500px;border-radius:0.75rem;border:1px solid var(--rs-border,#334155)"></div>`;
			this.#initMap(listings);
			return;
		}

		// Grid view
		if (listings.length === 0) {
			container.innerHTML = `
				<div style="text-align:center;padding:3rem;color:var(--rs-text-muted,#94a3b8)">
					<div style="font-size:2.5rem;margin-bottom:1rem">\u{1F3E0}</div>
					<p>No listings found. Try adjusting your search or filters.</p>
				</div>
			`;
			return;
		}

		container.innerHTML = `<div class="bnb-grid">${listings.map((l: any) => this.#renderListingCard(l)).join('')}</div>`;

		// Wire card clicks
		for (const card of container.querySelectorAll('.bnb-card')) {
			card.addEventListener('click', () => {
				const listingId = (card as HTMLElement).dataset.listingId;
				if (listingId) this.#showListingStays(listingId);
			});
		}
	}

	#renderListingCard(l: any): string {
		const eco = ECONOMY_BADGE[l.economy] || ECONOMY_BADGE.gift;
		const typeIcon = TYPE_ICONS[l.type] || '\u{1F3E8}';
		const typeLabel = (l.type || 'room').replace(/_/g, ' ');

		return `
			<div class="bnb-card" data-listing-id="${l.id}" data-collab-id="listing:${l.id}">
				<div class="bnb-card__cover">${typeIcon}</div>
				<div class="bnb-card__body">
					<div class="bnb-card__title">${this.#esc(l.title)}</div>
					<div class="bnb-card__host">
						<span>${this.#esc(l.host_name)}</span>
						${l.instant_accept ? '<span style="font-size:0.7rem;padding:0.1rem 0.3rem;border-radius:9999px;background:rgba(52,211,153,0.12);color:#34d399">\u{26A1} Auto</span>' : ''}
					</div>
					<div class="bnb-card__meta">
						<span class="bnb-badge ${eco.cls}">${eco.icon} ${eco.label}</span>
						<span class="bnb-badge bnb-badge--type">${typeIcon} ${typeLabel}</span>
						<span class="bnb-badge" style="background:rgba(148,163,184,0.08);color:#94a3b8;border:1px solid rgba(148,163,184,0.15)">\u{1F465} ${l.guest_capacity}</span>
					</div>
					<div class="bnb-card__location">\u{1F4CD} ${this.#esc(l.location_name)}</div>
				</div>
			</div>
		`;
	}

	async #initMap(listings: any[]) {
		try {
			await ensureLeaflet();
		} catch { return; }

		const L = (window as any).L;
		const mapEl = this.querySelector('#bnb-map');
		if (!mapEl) return;

		// Destroy previous map if any
		if (this.#map) { this.#map.remove(); this.#map = null; }

		this.#map = L.map(mapEl).setView([50, 10], 4);
		L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
			attribution: '&copy; OpenStreetMap',
			maxZoom: 18,
		}).addTo(this.#map);

		const bounds: [number, number][] = [];

		for (const l of listings) {
			if (!l.location_lat || !l.location_lng) continue;
			const latlng: [number, number] = [l.location_lat, l.location_lng];
			bounds.push(latlng);

			const eco = ECONOMY_BADGE[l.economy] || ECONOMY_BADGE.gift;
			const typeIcon = TYPE_ICONS[l.type] || '\u{1F3E8}';

			const marker = L.marker(latlng).addTo(this.#map);
			marker.bindPopup(`
				<div style="min-width:180px">
					<strong>${typeIcon} ${this.#esc(l.title)}</strong><br>
					<span style="font-size:0.85em;color:#666">${this.#esc(l.host_name)}</span><br>
					<span style="font-size:0.82em">${eco.icon} ${eco.label} &middot; \u{1F465} ${l.guest_capacity}</span><br>
					<span style="font-size:0.8em;color:#888">${this.#esc(l.location_name)}</span>
				</div>
			`);

			marker.on('click', () => this.#showListingStays(l.id));
		}

		if (bounds.length > 0) {
			this.#map.fitBounds(bounds, { padding: [30, 30], maxZoom: 10 });
		}
	}

	#showListingStays(listingId: string) {
		const listing = this.#listings.find((l: any) => l.id === listingId);
		const listingStays = this.#stays.filter((s: any) => s.listing_id === listingId);

		const sidebar = this.querySelector('#bnb-sidebar') as HTMLElement;
		const content = this.querySelector('#sidebar-content') as HTMLElement;
		if (!sidebar || !content) return;

		sidebar.style.display = 'block';

		const eco = ECONOMY_BADGE[listing?.economy] || ECONOMY_BADGE.gift;

		content.innerHTML = `
			<h3 style="margin:0 0 0.5rem;font-size:1rem;color:var(--rs-text,#e2e8f0)">${this.#esc(listing?.title || '')}</h3>
			<p style="font-size:0.82rem;color:var(--rs-text-muted,#94a3b8);margin:0 0 0.5rem">${this.#esc(listing?.description || '')}</p>
			<div style="display:flex;gap:0.5rem;margin-bottom:1rem">
				<span class="bnb-badge ${eco.cls}">${eco.icon} ${eco.label}</span>
				<span class="bnb-badge" style="background:rgba(148,163,184,0.08);color:#94a3b8;border:1px solid rgba(148,163,184,0.15)">\u{1F465} ${listing?.guest_capacity || 0}</span>
			</div>

			<h4 style="font-size:0.88rem;color:var(--rs-text,#e2e8f0);margin:1rem 0 0.75rem;border-top:1px solid var(--rs-border,#334155);padding-top:1rem">
				Stay Requests (${listingStays.length})
			</h4>
			${listingStays.length === 0
				? '<p style="font-size:0.82rem;color:var(--rs-text-muted,#64748b)">No stay requests yet.</p>'
				: listingStays.map((s: any) => `
					<div class="stay-item" data-stay-id="${s.id}" style="padding:0.75rem;margin-bottom:0.5rem;border:1px solid var(--rs-border,#334155);border-radius:0.5rem;cursor:pointer;transition:background 0.15s">
						<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.25rem">
							<span style="font-size:0.85rem;font-weight:600;color:var(--rs-text,#e2e8f0)">${this.#esc(s.guest_name)}</span>
							<span class="bnb-status bnb-status--${s.status}">${s.status}</span>
						</div>
						<div style="font-size:0.75rem;color:var(--rs-text-muted,#94a3b8)">
							${s.check_in ? new Date(s.check_in).toLocaleDateString() : ''} \u{2192} ${s.check_out ? new Date(s.check_out).toLocaleDateString() : ''}
							&middot; ${s.guest_count} guest${s.guest_count !== 1 ? 's' : ''}
							&middot; ${s.messages?.length || 0} msg${(s.messages?.length || 0) !== 1 ? 's' : ''}
						</div>
					</div>
				`).join('')}
		`;

		// Wire stay item clicks to show detail
		for (const item of content.querySelectorAll('.stay-item')) {
			item.addEventListener('click', () => {
				const stayId = (item as HTMLElement).dataset.stayId;
				const stay = this.#stays.find((s: any) => s.id === stayId);
				if (stay) this.#showStayDetail(stay);
			});
		}
	}

	#showStayDetail(stay: any) {
		const content = this.querySelector('#sidebar-content') as HTMLElement;
		if (!content) return;

		content.innerHTML = `
			<button id="back-to-listing" style="background:none;border:none;color:var(--rs-text-muted,#94a3b8);cursor:pointer;font-size:0.82rem;margin-bottom:0.75rem;padding:0">
				\u{2190} Back to listing
			</button>
			<folk-stay-request stay-id="${stay.id}" space="${this.#space}"></folk-stay-request>
		`;

		content.querySelector('#back-to-listing')?.addEventListener('click', () => {
			this.#showListingStays(stay.listing_id);
		});
	}

	#closeSidebar() {
		const sidebar = this.querySelector('#bnb-sidebar') as HTMLElement;
		if (sidebar) sidebar.style.display = 'none';
	}

	async #handleStayAction(stayId: string, action: string) {
		try {
			const res = await fetch(`${getModuleApiBase("rbnb")}/api/stays/${stayId}/${action}`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
			});
			if (res.ok) {
				await this.#loadData();
				const stay = this.#stays.find((s: any) => s.id === stayId);
				if (stay) this.#showStayDetail(stay);
			}
		} catch (err) {
			console.warn('[rBnb] Action failed:', err);
		}
	}

	async #handleStayMessage(stayId: string, body: string) {
		try {
			const res = await fetch(`${getModuleApiBase("rbnb")}/api/stays/${stayId}/messages`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({ body, sender_name: 'You' }),
			});
			if (res.ok) {
				await this.#loadData();
				const stay = this.#stays.find((s: any) => s.id === stayId);
				if (stay) this.#showStayDetail(stay);
			}
		} catch (err) {
			console.warn('[rBnb] Message failed:', err);
		}
	}

	#esc(s: string): string {
		const el = document.createElement('span');
		el.textContent = s || '';
		return el.innerHTML;
	}

	startTour() { this.#tour?.start(); }
}

if (!customElements.get('folk-bnb-view')) {
	customElements.define('folk-bnb-view', FolkBnbView);
}

export { FolkBnbView };
