import { FolkShape } from "./folk-shape";
import { css, html } from "./tags";

const styles = css`
	:host {
		background: var(--rs-bg-surface, #fff);
		color: var(--rs-text-primary, #1e293b);
		border-radius: 8px;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
		min-width: 300px;
		min-height: 200px;
	}

	.header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 8px 12px;
		background: #eab308;
		color: white;
		border-radius: 8px 8px 0 0;
		font-size: 12px;
		font-weight: 600;
		cursor: move;
	}

	.header-title {
		display: flex;
		align-items: center;
		gap: 6px;
	}

	.favicon {
		width: 16px;
		height: 16px;
		border-radius: 2px;
	}

	.header-actions {
		display: flex;
		gap: 4px;
	}

	.header-actions button {
		background: transparent;
		border: none;
		color: white;
		cursor: pointer;
		padding: 2px 6px;
		border-radius: 4px;
		font-size: 14px;
	}

	.header-actions button:hover {
		background: rgba(255, 255, 255, 0.2);
	}

	.content {
		width: 100%;
		height: calc(100% - 36px);
		position: relative;
	}

	.url-input-container {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		height: 100%;
		padding: 24px;
		gap: 12px;
	}

	.url-input {
		width: 100%;
		max-width: 400px;
		padding: 12px 16px;
		border: 2px solid var(--rs-input-border, #e2e8f0);
		border-radius: 8px;
		font-size: 14px;
		outline: none;
		background: var(--rs-input-bg, #fff);
		color: var(--rs-input-text, inherit);
	}

	.url-input:focus {
		border-color: #eab308;
	}

	.url-error {
		color: #ef4444;
		font-size: 12px;
	}

	.embed-iframe {
		width: 100%;
		height: 100%;
		border: none;
		border-radius: 0 0 8px 8px;
	}

	.unsupported {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		height: 100%;
		padding: 24px;
		gap: 12px;
		text-align: center;
		color: #64748b;
	}

	.open-link {
		background: #eab308;
		color: white;
		border: none;
		border-radius: 6px;
		padding: 8px 16px;
		cursor: pointer;
		font-size: 14px;
	}

	.open-link:hover {
		background: #ca8a04;
	}
`;

// URL transformation patterns
function transformUrl(url: string): string | null {
	try {
		const parsed = new URL(url);
		const hostname = parsed.hostname.replace("www.", "");

		// YouTube
		const youtubeMatch = url.match(
			/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
		);
		if (youtubeMatch) {
			return `https://www.youtube.com/embed/${youtubeMatch[1]}`;
		}

		// Twitter/X
		const twitterMatch = url.match(
			/(?:twitter\.com|x\.com)\/([^\/\s?]+)(?:\/(?:status|tweets)\/(\d+)|$)/
		);
		if (twitterMatch) {
			if (twitterMatch[2]) {
				// Tweet embed
				return `https://platform.x.com/embed/Tweet.html?id=${twitterMatch[2]}`;
			}
			// Profile - not embeddable
			return null;
		}

		// Google Maps
		if (hostname.includes("google") && parsed.pathname.includes("/maps")) {
			// Already an embed URL
			if (parsed.pathname.includes("/embed")) return url;
			// Convert place/directions URLs would need API key
			return url;
		}

		// Gather.town
		if (hostname === "app.gather.town") {
			return url.replace("app.gather.town", "gather.town/embed");
		}

		// Medium - not embeddable
		if (hostname.includes("medium.com")) {
			return null;
		}

		// Pass through other URLs
		return url;
	} catch {
		return null;
	}
}

function getFaviconUrl(url: string): string {
	try {
		const hostname = new URL(url).hostname;
		return `https://www.google.com/s2/favicons?domain=${hostname}&sz=32`;
	} catch {
		return "";
	}
}

function getDisplayTitle(url: string): string {
	try {
		const hostname = new URL(url).hostname.replace("www.", "");
		if (hostname.includes("youtube")) return "YouTube";
		if (hostname.includes("twitter") || hostname.includes("x.com")) return "Twitter/X";
		if (hostname.includes("google") && url.includes("/maps")) return "Google Maps";
		return hostname;
	} catch {
		return "Embed";
	}
}

declare global {
	interface HTMLElementTagNameMap {
		"folk-embed": FolkEmbed;
	}
}

export class FolkEmbed extends FolkShape {
	static override tagName = "folk-embed";

	static {
		const sheet = new CSSStyleSheet();
		const parentRules = Array.from(FolkShape.styles.cssRules)
			.map((r) => r.cssText)
			.join("\n");
		const childRules = Array.from(styles.cssRules)
			.map((r) => r.cssText)
			.join("\n");
		sheet.replaceSync(`${parentRules}\n${childRules}`);
		this.styles = sheet;
	}

	#url: string | null = null;
	#error: string | null = null;
	#embedRendered = false;

	get url() {
		return this.#url;
	}

	set url(value: string | null) {
		this.#url = value;
		this.requestUpdate("url");
		this.dispatchEvent(new CustomEvent("url-change", { detail: { url: value } }));
	}

	override createRenderRoot() {
		const root = super.createRenderRoot();

		this.#url = this.getAttribute("url") || null;

		const wrapper = document.createElement("div");
		wrapper.innerHTML = html`
			<div class="header">
				<span class="header-title">
					<span>🔗</span>
					<span class="title-text">Embed</span>
				</span>
				<div class="header-actions">
					<button class="close-btn" title="Close">×</button>
				</div>
			</div>
			<div class="content">
				<div class="url-input-container">
					<input
						type="text"
						class="url-input"
						placeholder="Enter URL to embed (YouTube, Twitter, etc.)..."
					/>
					<span class="url-error" style="display: none;"></span>
				</div>
			</div>
		`;

		// Replace the container div (slot's parent) with our wrapper
		const slot = root.querySelector("slot");
		const containerDiv = slot?.parentElement as HTMLElement;
		if (containerDiv) {
			containerDiv.replaceWith(wrapper);
		}

		const content = wrapper.querySelector(".content") as HTMLElement;
		const urlInputContainer = wrapper.querySelector(".url-input-container") as HTMLElement;
		const urlInput = wrapper.querySelector(".url-input") as HTMLInputElement;
		const urlError = wrapper.querySelector(".url-error") as HTMLElement;
		const titleText = wrapper.querySelector(".title-text") as HTMLElement;
		const headerTitle = wrapper.querySelector(".header-title") as HTMLElement;
		const closeBtn = wrapper.querySelector(".close-btn") as HTMLButtonElement;

		// Handle URL input
		const handleUrlSubmit = () => {
			let inputUrl = urlInput.value.trim();
			if (!inputUrl) return;

			// Auto-complete https://
			if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) {
				inputUrl = `https://${inputUrl}`;
			}

			// Validate URL
			const isValid = inputUrl.match(/(^\w+:|^)\/\//);
			if (!isValid) {
				this.#error = "Please enter a valid URL";
				urlError.textContent = this.#error;
				urlError.style.display = "block";
				return;
			}

			// Transform and set URL
			const embedUrl = transformUrl(inputUrl);
			this.url = inputUrl;
			this.#renderEmbed(content, urlInputContainer, titleText, headerTitle, inputUrl, embedUrl);
		};

		urlInput.addEventListener("keydown", (e) => {
			if (e.key === "Enter") {
				e.preventDefault();
				handleUrlSubmit();
			}
		});

		urlInput.addEventListener("blur", () => {
			if (urlInput.value.trim()) {
				handleUrlSubmit();
			}
		});

		// Close button
		closeBtn.addEventListener("click", (e) => {
			e.stopPropagation();
			this.dispatchEvent(new CustomEvent("close"));
		});

		// Defer embed rendering until shape enters viewport
		if (this.#url) {
			if (this.hasBeenVisible) {
				const embedUrl = transformUrl(this.#url);
				this.#renderEmbed(content, urlInputContainer, titleText, headerTitle, this.#url, embedUrl);
			} else {
				// Show URL text as lightweight placeholder
				titleText.textContent = getDisplayTitle(this.#url);
			}
		}

		return root;
	}

	protected override onBecameVisible(): void {
		if (this.#url && !this.#embedRendered) {
			const root = this.renderRoot as ShadowRoot;
			const content = root.querySelector(".content") as HTMLElement;
			const urlInputContainer = root.querySelector(".url-input-container") as HTMLElement;
			const titleText = root.querySelector(".title-text") as HTMLElement;
			const headerTitle = root.querySelector(".header-title") as HTMLElement;
			if (content && urlInputContainer && titleText && headerTitle) {
				const embedUrl = transformUrl(this.#url);
				this.#renderEmbed(content, urlInputContainer, titleText, headerTitle, this.#url, embedUrl);
			}
		}
	}

	#renderEmbed(
		content: HTMLElement,
		urlInputContainer: HTMLElement,
		titleText: HTMLElement,
		headerTitle: HTMLElement,
		originalUrl: string,
		embedUrl: string | null
	) {
		this.#embedRendered = true;
		// Update header
		titleText.textContent = getDisplayTitle(originalUrl);
		const favicon = document.createElement("img");
		favicon.className = "favicon";
		favicon.src = getFaviconUrl(originalUrl);
		favicon.onerror = () => (favicon.style.display = "none");
		headerTitle.insertBefore(favicon, titleText);

		if (!embedUrl) {
			// Unsupported content
			urlInputContainer.innerHTML = `
				<div class="unsupported">
					<p>This content cannot be embedded in an iframe.</p>
					<button class="open-link">Open in new tab →</button>
				</div>
			`;
			const openBtn = urlInputContainer.querySelector(".open-link");
			openBtn?.addEventListener("click", () => {
				window.open(originalUrl, "_blank", "noopener,noreferrer");
			});
		} else {
			// Create iframe
			urlInputContainer.style.display = "none";

			const iframe = document.createElement("iframe");
			iframe.className = "embed-iframe";
			iframe.src = embedUrl;
			iframe.loading = "lazy";
			iframe.allow =
				"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture";
			iframe.allowFullscreen = true;
			iframe.referrerPolicy = "no-referrer";
			iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups allow-presentation");

			content.appendChild(iframe);
		}
	}

	static override fromData(data: Record<string, any>): FolkEmbed {
		const shape = FolkShape.fromData(data) as FolkEmbed;
		if (data.url) shape.url = data.url;
		return shape;
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-embed",
			url: this.url,
		};
	}

	override applyData(data: Record<string, any>): void {
		super.applyData(data);
		if ("url" in data && this.url !== data.url) {
			this.url = data.url;
		}
	}
}
