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

const styles = css`
	:host {
		background: white;
		border-radius: 8px;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
		min-width: 400px;
		min-height: 450px;
	}

	.header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 8px 12px;
		background: linear-gradient(135deg, #0ea5e9, #6366f1);
		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;
	}

	.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 {
		display: flex;
		flex-direction: column;
		height: calc(100% - 36px);
		overflow: hidden;
	}

	.messages {
		flex: 1;
		overflow-y: auto;
		padding: 12px;
		display: flex;
		flex-direction: column;
		gap: 12px;
	}

	.message {
		max-width: 85%;
		padding: 10px 14px;
		border-radius: 12px;
		font-size: 13px;
		line-height: 1.5;
	}

	.message.user {
		align-self: flex-end;
		background: linear-gradient(135deg, #0ea5e9, #6366f1);
		color: white;
		border-bottom-right-radius: 4px;
	}

	.message.assistant {
		align-self: flex-start;
		background: #f1f5f9;
		color: #1e293b;
		border-bottom-left-radius: 4px;
	}

	.message.streaming {
		background: #f1f5f9;
	}

	.message.streaming::after {
		content: "▌";
		animation: blink 1s infinite;
	}

	@keyframes blink {
		0%, 100% { opacity: 1; }
		50% { opacity: 0; }
	}

	.placeholder {
		flex: 1;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		color: #94a3b8;
		text-align: center;
		gap: 8px;
		padding: 24px;
	}

	.placeholder-icon {
		font-size: 48px;
		opacity: 0.5;
	}

	.input-area {
		padding: 12px;
		border-top: 1px solid #e2e8f0;
		display: flex;
		flex-direction: column;
		gap: 8px;
	}

	.model-select {
		padding: 6px 10px;
		border: 2px solid #e2e8f0;
		border-radius: 6px;
		font-size: 12px;
		background: white;
		cursor: pointer;
		width: fit-content;
	}

	.prompt-row {
		display: flex;
		gap: 8px;
	}

	.prompt-input {
		flex: 1;
		padding: 10px 14px;
		border: 2px solid #e2e8f0;
		border-radius: 8px;
		font-size: 13px;
		resize: none;
		outline: none;
		font-family: inherit;
	}

	.prompt-input:focus {
		border-color: #6366f1;
	}

	.send-btn {
		padding: 10px 16px;
		background: linear-gradient(135deg, #0ea5e9, #6366f1);
		color: white;
		border: none;
		border-radius: 8px;
		font-size: 16px;
		cursor: pointer;
		transition: opacity 0.2s;
	}

	.send-btn:hover {
		opacity: 0.9;
	}

	.send-btn:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}

	.error {
		color: #ef4444;
		padding: 12px;
		background: #fef2f2;
		border-radius: 6px;
		font-size: 13px;
		margin: 12px;
	}

	.clear-btn {
		font-size: 12px;
		padding: 4px 8px;
		background: #f1f5f9;
		border: none;
		border-radius: 4px;
		cursor: pointer;
		color: #64748b;
	}

	.clear-btn:hover {
		background: #e2e8f0;
	}

	pre {
		background: #1e293b;
		color: #e2e8f0;
		padding: 12px;
		border-radius: 6px;
		overflow-x: auto;
		font-size: 12px;
		margin: 8px 0;
	}

	code {
		font-family: "Monaco", "Consolas", monospace;
	}
`;

export interface ChatMessage {
	id: string;
	role: "user" | "assistant";
	content: string;
	timestamp: Date;
}

declare global {
	interface HTMLElementTagNameMap {
		"folk-prompt": FolkPrompt;
	}
}

export class FolkPrompt extends FolkShape {
	static override tagName = "folk-prompt";

	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;
	}

	#messages: ChatMessage[] = [];
	#isStreaming = false;
	#error: string | null = null;
	#model = "gemini-1.5-flash";

	#messagesEl: HTMLElement | null = null;
	#promptInput: HTMLTextAreaElement | null = null;
	#modelSelect: HTMLSelectElement | null = null;
	#sendBtn: HTMLButtonElement | null = null;

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

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

		const wrapper = document.createElement("div");
		wrapper.innerHTML = html`
			<div class="header">
				<span class="header-title">
					<span>💬</span>
					<span>AI Prompt</span>
				</span>
				<div class="header-actions">
					<button class="clear-btn" title="Clear chat">Clear</button>
					<button class="close-btn" title="Close">×</button>
				</div>
			</div>
			<div class="content">
				<div class="messages">
					<div class="placeholder">
						<span class="placeholder-icon">🤖</span>
						<span>Ask me anything!</span>
						<span style="font-size: 11px;">I can help with code, writing, analysis, and more</span>
					</div>
				</div>
				<div class="input-area">
					<select class="model-select">
						<option value="gemini-1.5-flash">Gemini Flash</option>
						<option value="gemini-1.5-pro">Gemini Pro</option>
						<option value="claude-3-haiku">Claude Haiku</option>
						<option value="claude-3-sonnet">Claude Sonnet</option>
					</select>
					<div class="prompt-row">
						<textarea class="prompt-input" placeholder="Type your message..." rows="2"></textarea>
						<button class="send-btn">→</button>
					</div>
				</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);
		}

		this.#messagesEl = wrapper.querySelector(".messages");
		this.#promptInput = wrapper.querySelector(".prompt-input");
		this.#modelSelect = wrapper.querySelector(".model-select");
		this.#sendBtn = wrapper.querySelector(".send-btn");
		const clearBtn = wrapper.querySelector(".clear-btn") as HTMLButtonElement;
		const closeBtn = wrapper.querySelector(".close-btn") as HTMLButtonElement;

		// Send button
		this.#sendBtn?.addEventListener("click", (e) => {
			e.stopPropagation();
			this.#send();
		});

		// Enter key (without shift)
		this.#promptInput?.addEventListener("keydown", (e) => {
			if (e.key === "Enter" && !e.shiftKey) {
				e.preventDefault();
				this.#send();
			}
		});

		// Model select
		this.#modelSelect?.addEventListener("change", () => {
			this.#model = this.#modelSelect?.value || "gemini-1.5-flash";
		});

		// Clear button
		clearBtn.addEventListener("click", (e) => {
			e.stopPropagation();
			this.#clearChat();
		});

		// Prevent drag on inputs
		this.#promptInput?.addEventListener("pointerdown", (e) => e.stopPropagation());

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

		return root;
	}

	async #send() {
		const content = this.#promptInput?.value.trim();
		if (!content || this.#isStreaming) return;

		// Add user message
		const userMessage: ChatMessage = {
			id: crypto.randomUUID(),
			role: "user",
			content,
			timestamp: new Date(),
		};
		this.#messages.push(userMessage);

		// Clear input
		if (this.#promptInput) this.#promptInput.value = "";

		this.#isStreaming = true;
		this.#error = null;
		if (this.#sendBtn) this.#sendBtn.disabled = true;
		this.#renderMessages(true);

		try {
			const response = await fetch("/api/prompt", {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					messages: this.#messages.map((m) => ({
						role: m.role,
						content: m.content,
					})),
					model: this.#model,
				}),
			});

			if (!response.ok) {
				throw new Error(`Request failed: ${response.statusText}`);
			}

			const result = await response.json();

			const assistantMessage: ChatMessage = {
				id: crypto.randomUUID(),
				role: "assistant",
				content: result.content || result.text || result.message,
				timestamp: new Date(),
			};
			this.#messages.push(assistantMessage);

			this.dispatchEvent(
				new CustomEvent("message", { detail: { message: assistantMessage } })
			);
		} catch (error) {
			this.#error = error instanceof Error ? error.message : "Request failed";
			// Remove the user message if we failed
			this.#messages.pop();
		} finally {
			this.#isStreaming = false;
			if (this.#sendBtn) this.#sendBtn.disabled = false;
			this.#renderMessages(false);
		}
	}

	#clearChat() {
		this.#messages = [];
		this.#error = null;
		this.#renderMessages(false);
	}

	#renderMessages(streaming: boolean) {
		if (!this.#messagesEl) return;

		if (this.#messages.length === 0 && !this.#error) {
			this.#messagesEl.innerHTML = `
				<div class="placeholder">
					<span class="placeholder-icon">🤖</span>
					<span>Ask me anything!</span>
					<span style="font-size: 11px;">I can help with code, writing, analysis, and more</span>
				</div>
			`;
			return;
		}

		let messagesHtml = this.#messages
			.map((msg) => `<div class="message ${msg.role}">${this.#formatContent(msg.content)}</div>`)
			.join("");

		if (streaming) {
			messagesHtml += '<div class="message assistant streaming"></div>';
		}

		if (this.#error) {
			messagesHtml += `<div class="error">${this.#escapeHtml(this.#error)}</div>`;
		}

		this.#messagesEl.innerHTML = messagesHtml;
		this.#messagesEl.scrollTop = this.#messagesEl.scrollHeight;
	}

	#formatContent(content: string): string {
		// Simple markdown-like formatting
		let html = this.#escapeHtml(content);

		// Code blocks
		html = html.replace(/```(\w*)\n([\s\S]*?)```/g, "<pre><code>$2</code></pre>");

		// Inline code
		html = html.replace(/`([^`]+)`/g, "<code>$1</code>");

		// Bold
		html = html.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");

		// Line breaks
		html = html.replace(/\n/g, "<br>");

		return html;
	}

	#escapeHtml(text: string): string {
		const div = document.createElement("div");
		div.textContent = text;
		return div.innerHTML;
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-prompt",
			model: this.#model,
			messages: this.messages.map((msg) => ({
				...msg,
				timestamp: msg.timestamp.toISOString(),
			})),
		};
	}
}
