/**
 * <folk-swag-designer> — upload artwork → generate print-ready files.
 * Product selector (sticker, poster, tee, hoodie), image upload with preview,
 * generate button, artifact result display with download link.
 *
 * Demo mode: 4-step interactive flow with inline SVG mockups,
 * provider matching, revenue splits, and pipeline visualization.
 */

// --- Demo data (self-contained, zero API calls in demo mode) ---

interface DemoProduct {
	id: string;
	name: string;
	printArea: string;
	baseCost: string;
	printful: boolean;
	sizes?: string[];
	colors?: { id: string; name: string; hex: string }[];
}

interface DemoProvider {
	name: string;
	type: "cosmolocal" | "global";
	city: string;
	lat: number;
	lng: number;
	capabilities: string[];
	unitCost: number;
	turnaround: string;
}

const DEMO_PRODUCTS: DemoProduct[] = [
	{
		id: "tee", name: "T-Shirt", printArea: "305×406mm", baseCost: "$9.25–$13.25",
		printful: true,
		sizes: ["S", "M", "L", "XL", "2XL", "3XL"],
		colors: [
			{ id: "black", name: "Black", hex: "#0a0a0a" },
			{ id: "white", name: "White", hex: "#ffffff" },
			{ id: "forest_green", name: "Forest Green", hex: "#2d4a3e" },
			{ id: "heather_charcoal", name: "Heather Charcoal", hex: "#4a4a4a" },
			{ id: "maroon", name: "Maroon", hex: "#5a2d2d" },
		],
	},
	{
		id: "sticker", name: "Sticker Sheet", printArea: "210×297mm", baseCost: "$1.20–$1.50",
		printful: true,
	},
	{
		id: "poster", name: "Poster (A3)", printArea: "297×420mm", baseCost: "$4.50–$7.00",
		printful: false,
	},
	{
		id: "hoodie", name: "Hoodie", printArea: "356×406mm", baseCost: "$23.95–$27.95",
		printful: true,
		sizes: ["S", "M", "L", "XL", "2XL"],
		colors: [
			{ id: "black", name: "Black", hex: "#0a0a0a" },
			{ id: "dark_grey_heather", name: "Dark Grey Heather", hex: "#3a3a3a" },
		],
	},
];

const DEMO_PROVIDERS: DemoProvider[] = [
	{ name: "De Drukker Collective", type: "cosmolocal", city: "Amsterdam", lat: 52.37, lng: 4.90, capabilities: ["dtg-print", "vinyl-cut", "screen-print"], unitCost: 8.50, turnaround: "3-4 days" },
	{ name: "Kuona Print Collective", type: "cosmolocal", city: "Nairobi", lat: -1.29, lng: 36.82, capabilities: ["dtg-print", "screen-print", "vinyl-cut"], unitCost: 5.50, turnaround: "5-7 days" },
	{ name: "Grafica Popular", type: "cosmolocal", city: "Sao Paulo", lat: -23.55, lng: -46.63, capabilities: ["screen-print", "risograph", "inkjet-print"], unitCost: 6.00, turnaround: "4-6 days" },
	{ name: "Printful", type: "global", city: "Global", lat: 0, lng: 0, capabilities: ["dtg-print", "vinyl-cut", "inkjet-print"], unitCost: 9.25, turnaround: "5-7 days" },
];

const DEMO_BUYER = { lat: 52.52, lng: 13.41 }; // Berlin

function haversineKm(lat1: number, lng1: number, lat2: number, lng2: number): number {
	const R = 6371;
	const dLat = (lat2 - lat1) * Math.PI / 180;
	const dLng = (lng2 - lng1) * Math.PI / 180;
	const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng / 2) ** 2;
	return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

// --- SVG generators ---

function cosmoDesignSvg(): string {
	return `<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
		<rect width="200" height="200" fill="#0f172a"/>
		<circle cx="100" cy="100" r="70" fill="none" stroke="#6366f1" stroke-width="1.5" opacity="0.4"/>
		<circle cx="100" cy="100" r="50" fill="none" stroke="#818cf8" stroke-width="1.5" opacity="0.6"/>
		<circle cx="100" cy="100" r="30" fill="none" stroke="#a5b4fc" stroke-width="1.5" opacity="0.8"/>
		<circle cx="100" cy="100" r="10" fill="#6366f1"/>
		${Array.from({length: 12}, (_, i) => {
			const a = i * 30 * Math.PI / 180;
			return `<line x1="${100 + 15 * Math.cos(a)}" y1="${100 + 15 * Math.sin(a)}" x2="${100 + 75 * Math.cos(a)}" y2="${100 + 75 * Math.sin(a)}" stroke="#818cf8" stroke-width="1" opacity="0.3"/>`;
		}).join("")}
		<circle cx="100" cy="100" r="5" fill="#e2e8f0"/>
		<text x="100" y="160" text-anchor="middle" fill="#94a3b8" font-size="8" font-family="system-ui">COSMOLOCAL</text>
		<text x="100" y="170" text-anchor="middle" fill="#64748b" font-size="6" font-family="system-ui">NETWORK</text>
	</svg>`;
}

function teeMockupSvg(color: string): string {
	return `<svg viewBox="0 0 240 300" xmlns="http://www.w3.org/2000/svg">
		<path d="M60,40 L30,60 L10,120 L40,130 L50,90 L50,280 L190,280 L190,90 L200,130 L230,120 L210,60 L180,40 L160,55 Q140,70 120,70 Q100,70 80,55 Z" fill="${color}" stroke="#475569" stroke-width="1.5"/>
		<defs><clipPath id="tee-clip"><rect x="80" y="90" width="80" height="107" rx="4"/></clipPath></defs>
		<g clip-path="url(#tee-clip)" transform="translate(80,90)">
			<svg viewBox="0 0 200 200" width="80" height="80" y="13">${cosmoDesignSvg().replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg>
		</g>
		<rect x="80" y="90" width="80" height="107" rx="4" fill="none" stroke="#6366f1" stroke-width="0.75" stroke-dasharray="3,2" opacity="0.5"/>
	</svg>`;
}

function hoodieMockupSvg(color: string): string {
	return `<svg viewBox="0 0 260 310" xmlns="http://www.w3.org/2000/svg">
		<path d="M65,50 L30,70 L5,140 L40,150 L55,100 L55,290 L205,290 L205,100 L220,150 L255,140 L230,70 L195,50 L175,60 Q155,80 130,85 Q105,80 85,60 Z" fill="${color}" stroke="#475569" stroke-width="1.5"/>
		<path d="M85,60 Q105,30 130,25 Q155,30 175,60 Q155,80 130,85 Q105,80 85,60 Z" fill="${color}" stroke="#475569" stroke-width="1"/>
		<ellipse cx="130" cy="55" rx="20" ry="15" fill="#1e293b" stroke="#475569" stroke-width="1"/>
		<defs><clipPath id="hoodie-clip"><rect x="80" y="100" width="100" height="115" rx="4"/></clipPath></defs>
		<g clip-path="url(#hoodie-clip)" transform="translate(80,100)">
			<svg viewBox="0 0 200 200" width="100" height="100" y="8">${cosmoDesignSvg().replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg>
		</g>
		<rect x="80" y="100" width="100" height="115" rx="4" fill="none" stroke="#6366f1" stroke-width="0.75" stroke-dasharray="3,2" opacity="0.5"/>
	</svg>`;
}

function stickerMockupSvg(): string {
	return `<svg viewBox="0 0 240 240" xmlns="http://www.w3.org/2000/svg">
		<rect x="20" y="20" width="200" height="200" rx="16" fill="#1e293b" stroke="#475569" stroke-width="1.5"/>
		<rect x="30" y="30" width="180" height="180" rx="12" fill="none" stroke="#6366f1" stroke-width="1" stroke-dasharray="4,3" opacity="0.5"/>
		<g transform="translate(40,40)">
			<svg viewBox="0 0 200 200" width="160" height="160">${cosmoDesignSvg().replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg>
		</g>
		<text x="120" y="232" text-anchor="middle" fill="#64748b" font-size="7" font-family="system-ui">kiss-cut border</text>
	</svg>`;
}

function posterMockupSvg(): string {
	return `<svg viewBox="0 0 220 300" xmlns="http://www.w3.org/2000/svg">
		<rect x="15" y="15" width="190" height="270" fill="#1e293b" stroke="#475569" stroke-width="2"/>
		<rect x="25" y="25" width="170" height="250" fill="none" stroke="#334155" stroke-width="1"/>
		<g transform="translate(40,50)">
			<svg viewBox="0 0 200 200" width="140" height="140">${cosmoDesignSvg().replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg>
		</g>
		<text x="110" y="230" text-anchor="middle" fill="#94a3b8" font-size="10" font-family="system-ui" font-weight="600">COSMOLOCAL NETWORK</text>
		<text x="110" y="245" text-anchor="middle" fill="#64748b" font-size="7" font-family="system-ui">A3 — 297×420mm — 300 DPI</text>
	</svg>`;
}

// --- Component ---

class FolkSwagDesigner extends HTMLElement {
	private shadow: ShadowRoot;
	private space = "";
	private selectedProduct = "tee";
	private selectedSize = "M";
	private selectedColor = "black";
	private imageFile: File | null = null;
	private imagePreview = "";
	private designTitle = "";
	private generating = false;
	private artifact: any = null;
	private error = "";
	private demoStep: 1 | 2 | 3 | 4 = 1;
	private progressStep = 0;
	private usedSampleDesign = false;

	constructor() {
		super();
		this.shadow = this.attachShadow({ mode: "open" });
	}

	connectedCallback() {
		this.space = this.getAttribute("space") || "";
		if (this.space === "demo") {
			this.selectedProduct = "tee";
			this.selectedSize = "M";
			this.selectedColor = "black";
			this.designTitle = "Cosmolocal Network Tee";
			this.demoStep = 1;
			this.render();
			return;
		}
		this.render();
	}

	private getApiBase(): string {
		const match = window.location.pathname.match(/^\/([^/]+)\/rswag/);
		if (match) return `/${match[1]}/rswag`;
		if (this.space) return `/${this.space}/rswag`;
		return "/demo/rswag";
	}

	private getDemoProduct(): DemoProduct {
		return DEMO_PRODUCTS.find(p => p.id === this.selectedProduct) || DEMO_PRODUCTS[0];
	}

	private getAutoTitle(): string {
		const p = this.getDemoProduct();
		return `Cosmolocal Network ${p.name}`;
	}

	private demoSelectProduct(id: string) {
		this.selectedProduct = id;
		const p = this.getDemoProduct();
		this.selectedSize = p.sizes?.[1] || "";
		this.selectedColor = p.colors?.[0]?.id || "";
		this.designTitle = this.getAutoTitle();
		this.demoStep = 1;
		this.usedSampleDesign = false;
		this.artifact = null;
		this.render();
	}

	private demoUseSample() {
		this.usedSampleDesign = true;
		this.demoStep = 2;
		this.render();
	}

	private demoGenerate() {
		this.demoStep = 3;
		this.progressStep = 0;
		this.render();

		const steps = [1, 2, 3, 4];
		const delays = [400, 400, 400, 300];
		let elapsed = 0;
		for (const s of steps) {
			elapsed += delays[s - 1];
			setTimeout(() => {
				this.progressStep = s;
				if (s === 4) {
					this.buildDemoArtifact();
					this.demoStep = 4;
				}
				this.render();
			}, elapsed);
		}
	}

	private buildDemoArtifact() {
		const p = this.getDemoProduct();
		const dims: Record<string, { w: number; h: number }> = {
			tee: { w: 305, h: 406 }, sticker: { w: 210, h: 297 },
			poster: { w: 297, h: 420 }, hoodie: { w: 356, h: 406 },
		};
		const d = dims[p.id] || dims.tee;
		const wpx = Math.round((d.w / 25.4) * 300);
		const hpx = Math.round((d.h / 25.4) * 300);

		const capabilities: Record<string, string[]> = {
			tee: ["dtg-print"], sticker: ["vinyl-cut"], poster: ["inkjet-print"], hoodie: ["dtg-print"],
		};
		const substrates: Record<string, string[]> = {
			tee: ["cotton-standard", "cotton-organic"], sticker: ["vinyl-matte", "vinyl-gloss"],
			poster: ["paper-160gsm-cover", "paper-100gsm"], hoodie: ["cotton-polyester-blend"],
		};

		this.artifact = {
			title: this.designTitle || this.getAutoTitle(),
			product: p.id,
			spec: {
				product_type: p.id === "sticker" ? "sticker-sheet" : p.id,
				dimensions: { width_mm: d.w, height_mm: d.h },
				dpi: 300,
				color_space: "sRGB",
				required_capabilities: capabilities[p.id],
				substrates: substrates[p.id],
			},
			render_targets: {
				print: { format: "png", label: "Print-Ready PNG", dimensions: `${wpx}x${hpx} px`, url: "#demo-print" },
				preview: { format: "png", label: "Preview PNG", dimensions: `${Math.round(wpx / 4)}x${Math.round(hpx / 4)} px`, url: "#demo-preview" },
			},
			pricing: { creator_share: "35%", community_share: "15%", provider_share: "50%" },
			next_actions: [
				{ action: "ingest_to_rcart", label: "Send to rCart", url: "/demo/cart" },
				{ action: "edit_design", label: "Edit Design" },
				{ action: "save_to_rfiles", label: "Save to rFiles" },
			],
			...(this.selectedSize ? { size: this.selectedSize } : {}),
			...(this.selectedColor ? { color: this.selectedColor } : {}),
		};
	}

	private getMatchedProviders(): (DemoProvider & { distance: number })[] {
		const p = this.getDemoProduct();
		const cap = p.id === "sticker" ? "vinyl-cut" : p.id === "poster" ? "inkjet-print" : "dtg-print";
		return DEMO_PROVIDERS
			.filter(prov => prov.capabilities.includes(cap))
			.map(prov => ({
				...prov,
				distance: prov.type === "global" ? Infinity : Math.round(haversineKm(DEMO_BUYER.lat, DEMO_BUYER.lng, prov.lat, prov.lng)),
			}))
			.sort((a, b) => a.distance - b.distance);
	}

	private async generate() {
		if (this.space === "demo") {
			this.demoGenerate();
			return;
		}
		if (!this.imageFile || this.generating) return;
		this.generating = true;
		this.error = "";
		this.artifact = null;
		this.render();

		try {
			const formData = new FormData();
			formData.append("image", this.imageFile);
			formData.append("product", this.selectedProduct);
			formData.append("title", this.designTitle || "Untitled Design");

			const res = await fetch(`${this.getApiBase()}/api/artifact`, {
				method: "POST",
				body: formData,
			});

			if (!res.ok) {
				const err = await res.json();
				throw new Error(err.error || `Failed: ${res.status}`);
			}

			this.artifact = await res.json();
		} catch (e) {
			this.error = e instanceof Error ? e.message : "Generation failed";
		} finally {
			this.generating = false;
			this.render();
		}
	}

	private render() {
		if (this.space === "demo") {
			this.renderDemo();
		} else {
			this.renderFull();
		}
	}

	// ---- Demo mode rendering (4-step flow) ----

	private renderDemo() {
		const p = this.getDemoProduct();
		const isApparel = p.id === "tee" || p.id === "hoodie";

		this.shadow.innerHTML = `
		<style>${this.getDemoStyles()}</style>

		<!-- Step indicators -->
		<div class="steps-bar">
			${[
				{ n: 1, label: "Product" },
				{ n: 2, label: "Design" },
				{ n: 3, label: "Generate" },
				{ n: 4, label: "Pipeline" },
			].map(s => `<div class="step-dot ${this.demoStep >= s.n ? 'active' : ''} ${this.demoStep === s.n ? 'current' : ''}">
				<span class="step-num">${this.demoStep > s.n ? '&#10003;' : s.n}</span>
				<span class="step-label">${s.label}</span>
			</div>`).join('<div class="step-line"></div>')}
		</div>

		<!-- Step 1: Product Selection -->
		<section class="step-section ${this.demoStep >= 1 ? 'visible' : ''}">
			<div class="products">
				${DEMO_PRODUCTS.map(dp => `
					<div class="product ${this.selectedProduct === dp.id ? 'active' : ''}" data-product="${dp.id}">
						<div class="product-icon">${this.productIcon(dp.id)}</div>
						<div class="product-name">${dp.name}</div>
						<div class="product-specs">${dp.printArea}</div>
						<div class="product-cost">${dp.baseCost}</div>
						${dp.printful ? '<span class="badge badge-printful">Printful</span>' : '<span class="badge badge-local">cosmolocal only</span>'}
					</div>
				`).join("")}
			</div>

			${isApparel && p.sizes ? `
			<div class="option-row">
				<span class="option-label">Size</span>
				<div class="pills">
					${p.sizes.map(s => `<button class="pill ${this.selectedSize === s ? 'active' : ''}" data-size="${s}">${s}</button>`).join("")}
				</div>
			</div>` : ""}

			${isApparel && p.colors ? `
			<div class="option-row">
				<span class="option-label">Color</span>
				<div class="color-swatches">
					${p.colors.map(c => `<button class="swatch ${this.selectedColor === c.id ? 'active' : ''}" data-color="${c.id}" style="background:${c.hex}" title="${c.name}"></button>`).join("")}
				</div>
			</div>` : ""}
		</section>

		<!-- Step 2: Design Mockup (always visible alongside product selection) -->
		<section class="step-section visible">
			<div class="mockup-area">
				<div class="mockup-svg">${this.getMockupSvg()}</div>
				<div class="mockup-info">
					<h3 class="mockup-title">${this.esc(this.designTitle || this.getAutoTitle())}</h3>
					<div class="mockup-meta">${p.name} ${this.selectedSize ? `/ ${this.selectedSize}` : ""} ${this.selectedColor && p.colors ? `/ ${p.colors.find(c => c.id === this.selectedColor)?.name || ""}` : ""}</div>
					${!this.usedSampleDesign ? `<button class="btn btn-secondary sample-btn">Use Sample Design</button>` : '<span class="badge badge-ok">Sample design loaded</span>'}
				</div>
			</div>
		</section>

		<!-- Generate button (visible once sample design is loaded) -->
		${this.usedSampleDesign && this.demoStep < 3 ? `
		<div class="generate-row">
			<button class="btn btn-primary generate-btn">Generate Print-Ready Files</button>
		</div>` : ""}

		<!-- Step 3: Progress + Artifact + Providers -->
		${this.demoStep >= 3 ? this.renderStep3() : ""}

		<!-- Step 4: Pipeline Visualization -->
		${this.demoStep >= 4 ? this.renderStep4() : ""}
		`;

		this.bindDemoEvents();
	}

	private renderStep3(): string {
		const progressLabels = ["Processing image...", "Generating artifact...", "Matching providers...", "Done!"];

		let html = `<section class="step-section visible">`;

		// Progress bar (always show)
		html += `<div class="progress-bar">
			<div class="progress-fill" style="width:${this.progressStep * 25}%"></div>
		</div>
		<div class="progress-steps">
			${progressLabels.map((label, i) => `<span class="prog-label ${this.progressStep > i ? 'done' : this.progressStep === i + 1 ? 'active' : ''}">${this.progressStep > i + 1 ? '&#10003; ' : ''}${label}</span>`).join("")}
		</div>`;

		// Only show artifact + providers once done
		if (this.demoStep >= 4 && this.artifact) {
			const providers = this.getMatchedProviders();
			const selectedProvider = providers[0];
			const unitCost = selectedProvider?.unitCost || 9.25;
			const provAmt = (unitCost * 0.5).toFixed(2);
			const creatorAmt = (unitCost * 0.35).toFixed(2);
			const communityAmt = (unitCost * 0.15).toFixed(2);

			// Artifact card
			html += `
			<div class="artifact-card">
				<h3 class="artifact-heading">Artifact Envelope</h3>
				<div class="artifact-grid">
					<div class="artifact-field"><span class="af-label">Product</span><span class="af-value">${this.esc(this.artifact.spec.product_type)}</span></div>
					<div class="artifact-field"><span class="af-label">Dimensions</span><span class="af-value">${this.artifact.spec.dimensions.width_mm}×${this.artifact.spec.dimensions.height_mm}mm</span></div>
					<div class="artifact-field"><span class="af-label">DPI</span><span class="af-value">${this.artifact.spec.dpi}</span></div>
					<div class="artifact-field"><span class="af-label">Color Space</span><span class="af-value">${this.artifact.spec.color_space}</span></div>
					<div class="artifact-field"><span class="af-label">Capabilities</span><span class="af-value">${(this.artifact.spec.required_capabilities || []).join(", ")}</span></div>
					<div class="artifact-field"><span class="af-label">Substrates</span><span class="af-value">${(this.artifact.spec.substrates || []).join(", ")}</span></div>
				</div>
				<div class="artifact-targets">
					${Object.values(this.artifact.render_targets).map((t: any) => `<span class="target-chip">${t.label}: ${t.dimensions}</span>`).join("")}
				</div>
				<div class="artifact-actions">
					${(this.artifact.next_actions || []).map((a: any) => `<span class="action-chip">${a.label}</span>`).join("")}
				</div>
			</div>`;

			// Provider match table
			html += `
			<div class="provider-section">
				<h3 class="provider-heading">Provider Matching <span class="buyer-loc">(buyer: Berlin)</span></h3>
				<div class="provider-table">
					<div class="pt-header">
						<span>Provider</span><span>Type</span><span>City</span><span>Distance</span><span>Cost</span><span>Turnaround</span>
					</div>
					${providers.map((prov, i) => `
					<div class="pt-row ${i === 0 ? 'nearest' : ''}">
						<span class="pt-name">${prov.name}</span>
						<span><span class="badge ${prov.type === 'cosmolocal' ? 'badge-cosmo' : 'badge-global'}">${prov.type}</span></span>
						<span>${prov.city}</span>
						<span>${prov.distance === Infinity ? '--' : `~${prov.distance.toLocaleString()} km`}</span>
						<span class="pt-cost">$${prov.unitCost.toFixed(2)}</span>
						<span>${prov.turnaround}</span>
					</div>`).join("")}
				</div>
			</div>`;

			// Revenue split bar
			html += `
			<div class="split-section">
				<h4 class="split-heading">Revenue Split <span class="split-total">(from $${unitCost.toFixed(2)} unit cost)</span></h4>
				<div class="split-bar">
					<div class="split-seg split-provider" style="flex:50">Provider 50% <span class="split-amt">$${provAmt}</span></div>
					<div class="split-seg split-creator" style="flex:35">Creator 35% <span class="split-amt">$${creatorAmt}</span></div>
					<div class="split-seg split-community" style="flex:15"><span class="split-amt">$${communityAmt}</span></div>
				</div>
				<div class="split-legend"><span>Community 15%</span></div>
			</div>`;
		}

		html += `</section>`;
		return html;
	}

	private renderStep4(): string {
		return `
		<section class="step-section visible">
			<h3 class="pipeline-heading">Print-on-Demand Pipeline</h3>
			<div class="pipeline">
				<div class="pipe-node done"><div class="pipe-icon">${this.productIcon("tee")}</div><div class="pipe-label">rSwag Design</div><span class="pipe-check">&#10003;</span></div>
				<div class="pipe-arrow">&rarr;</div>
				<div class="pipe-node done"><div class="pipe-icon"><svg viewBox="0 0 20 20" width="24" height="24"><rect x="2" y="4" width="16" height="12" rx="2" fill="none" stroke="#818cf8" stroke-width="1.5"/><line x1="6" y1="8" x2="14" y2="8" stroke="#818cf8" stroke-width="1"/><line x1="6" y1="11" x2="12" y2="11" stroke="#818cf8" stroke-width="1"/></svg></div><div class="pipe-label">Artifact Spec</div><span class="pipe-check">&#10003;</span></div>
				<div class="pipe-arrow">&rarr;</div>
				<div class="pipe-node done"><div class="pipe-icon"><svg viewBox="0 0 20 20" width="24" height="24"><rect x="3" y="3" width="14" height="14" rx="3" fill="none" stroke="#818cf8" stroke-width="1.5"/><circle cx="10" cy="10" r="3" fill="#818cf8"/></svg></div><div class="pipe-label">rCart Catalog</div><span class="pipe-check">&#10003;</span></div>
				<div class="pipe-arrow">&rarr;</div>
				<div class="pipe-node done"><div class="pipe-icon"><svg viewBox="0 0 20 20" width="24" height="24"><circle cx="10" cy="8" r="4" fill="none" stroke="#818cf8" stroke-width="1.5"/><path d="M4,18 Q4,13 10,13 Q16,13 16,18" fill="none" stroke="#818cf8" stroke-width="1.5"/></svg></div><div class="pipe-label">Provider Match</div><span class="pipe-check">&#10003;</span></div>
				<div class="pipe-arrow">&rarr;</div>
				<div class="pipe-node done"><div class="pipe-icon"><svg viewBox="0 0 20 20" width="24" height="24"><rect x="3" y="5" width="14" height="10" rx="2" fill="none" stroke="#818cf8" stroke-width="1.5"/><path d="M3,8 L10,12 L17,8" fill="none" stroke="#818cf8" stroke-width="1.5"/></svg></div><div class="pipe-label">Local Print</div><span class="pipe-check">&#10003;</span></div>
			</div>
			<div class="pipeline-actions">
				<a class="btn btn-primary" href="/demo/cart">Send to rCart</a>
				<button class="btn btn-secondary json-toggle-btn">View Artifact JSON</button>
			</div>
			<pre class="json-pre">${this.esc(JSON.stringify(this.artifact, null, 2))}</pre>
		</section>`;
	}

	private productIcon(id: string): string {
		const icons: Record<string, string> = {
			tee: `<svg viewBox="0 0 24 24" width="28" height="28"><path d="M7,4 L4,6 L2,12 L5,13 L6,9 L6,22 L18,22 L18,9 L19,13 L22,12 L20,6 L17,4 L15,6 Q14,8 12,8 Q10,8 9,6 Z" fill="none" stroke="#818cf8" stroke-width="1.5" stroke-linejoin="round"/></svg>`,
			sticker: `<svg viewBox="0 0 24 24" width="28" height="28"><rect x="3" y="3" width="18" height="18" rx="4" fill="none" stroke="#818cf8" stroke-width="1.5"/><circle cx="12" cy="12" r="5" fill="none" stroke="#818cf8" stroke-width="1.5"/></svg>`,
			poster: `<svg viewBox="0 0 24 24" width="28" height="28"><rect x="4" y="2" width="16" height="20" rx="2" fill="none" stroke="#818cf8" stroke-width="1.5"/><line x1="8" y1="7" x2="16" y2="7" stroke="#818cf8" stroke-width="1"/><line x1="8" y1="10" x2="16" y2="10" stroke="#818cf8" stroke-width="1"/><rect x="8" y="13" width="8" height="5" rx="1" fill="none" stroke="#818cf8" stroke-width="1"/></svg>`,
			hoodie: `<svg viewBox="0 0 24 24" width="28" height="28"><path d="M7,5 L3,7 L1,14 L4,15 L5,10 L5,22 L19,22 L19,10 L20,15 L23,14 L21,7 L17,5 L15,7 Q14,9 12,9 Q10,9 9,7 Z" fill="none" stroke="#818cf8" stroke-width="1.5" stroke-linejoin="round"/><ellipse cx="12" cy="6" rx="3" ry="2" fill="none" stroke="#818cf8" stroke-width="1"/></svg>`,
		};
		return icons[id] || icons.tee;
	}

	private getMockupSvg(): string {
		const colorHex = this.getDemoProduct().colors?.find(c => c.id === this.selectedColor)?.hex || "#0a0a0a";
		switch (this.selectedProduct) {
			case "tee": return teeMockupSvg(colorHex);
			case "hoodie": return hoodieMockupSvg(colorHex);
			case "sticker": return stickerMockupSvg();
			case "poster": return posterMockupSvg();
			default: return teeMockupSvg(colorHex);
		}
	}

	private bindDemoEvents() {
		// Product selection
		this.shadow.querySelectorAll(".product").forEach(el => {
			el.addEventListener("click", () => this.demoSelectProduct((el as HTMLElement).dataset.product || "tee"));
		});
		// Size pills
		this.shadow.querySelectorAll(".pill[data-size]").forEach(el => {
			el.addEventListener("click", () => { this.selectedSize = (el as HTMLElement).dataset.size || "M"; this.render(); });
		});
		// Color swatches
		this.shadow.querySelectorAll(".swatch[data-color]").forEach(el => {
			el.addEventListener("click", () => { this.selectedColor = (el as HTMLElement).dataset.color || "black"; this.render(); });
		});
		// Sample design button
		this.shadow.querySelector(".sample-btn")?.addEventListener("click", () => this.demoUseSample());
		// Generate button
		this.shadow.querySelector(".generate-btn")?.addEventListener("click", () => this.demoGenerate());
		// JSON toggle
		this.shadow.querySelector(".json-toggle-btn")?.addEventListener("click", () => {
			const pre = this.shadow.querySelector(".json-pre");
			pre?.classList.toggle("visible");
		});
	}

	// ---- Full (non-demo) rendering ----

	private renderFull() {
		const products = [
			{ id: "sticker", name: "Sticker Sheet", icon: "📋", desc: "A4 vinyl stickers" },
			{ id: "poster", name: "Poster (A3)", icon: "🖼", desc: "A3 art print" },
			{ id: "tee", name: "T-Shirt", icon: "👕", desc: '12x16" DTG print' },
			{ id: "hoodie", name: "Hoodie", icon: "🧥", desc: '14x16" DTG print' },
		];

		this.shadow.innerHTML = `
		<style>
			:host { display: block; padding: 1.5rem; max-width: 900px; margin: 0 auto; }
			.products { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1.5rem; }
			.product { padding: 1rem; border-radius: 12px; border: 2px solid #334155; background: #1e293b; cursor: pointer; text-align: center; transition: all 0.15s; }
			.product:hover { border-color: #475569; }
			.product.active { border-color: #6366f1; background: rgba(99,102,241,0.1); }
			.product-icon { font-size: 2rem; margin-bottom: 0.375rem; }
			.product-name { color: #f1f5f9; font-weight: 600; font-size: 0.875rem; }
			.product-desc { color: #64748b; font-size: 0.75rem; margin-top: 0.25rem; }
			.upload-area { border: 2px dashed #334155; border-radius: 12px; padding: 2rem; text-align: center; margin-bottom: 1rem; cursor: pointer; transition: border-color 0.15s; background: #1e293b; }
			.upload-area:hover { border-color: #6366f1; }
			.upload-area.has-image { border-style: solid; border-color: #475569; }
			.upload-label { color: #94a3b8; font-size: 0.875rem; }
			.preview-img { max-width: 200px; max-height: 200px; border-radius: 8px; }
			.title-input { width: 100%; padding: 0.625rem 0.75rem; border: 1px solid #334155; border-radius: 8px; background: #1e293b; color: #f1f5f9; font-size: 0.875rem; margin-bottom: 1rem; box-sizing: border-box; }
			.title-input:focus { outline: none; border-color: #6366f1; }
			.generate-btn { width: 100%; padding: 0.75rem; border: none; border-radius: 8px; background: #4f46e5; color: #fff; font-size: 1rem; font-weight: 600; cursor: pointer; margin-bottom: 1rem; }
			.generate-btn:hover { background: #4338ca; }
			.generate-btn:disabled { opacity: 0.5; cursor: not-allowed; }
			.error { background: rgba(239,68,68,0.1); border: 1px solid #ef4444; border-radius: 8px; padding: 0.75rem; color: #fca5a5; font-size: 0.875rem; margin-bottom: 1rem; }
			.result { background: #1e293b; border: 1px solid #334155; border-radius: 12px; padding: 1.25rem; }
			.result-title { color: #f1f5f9; font-weight: 600; margin: 0 0 0.5rem; }
			.result-meta { color: #94a3b8; font-size: 0.8125rem; margin-bottom: 1rem; }
			.result-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; }
			.result-btn { padding: 0.5rem 1rem; border-radius: 8px; font-size: 0.875rem; text-decoration: none; font-weight: 500; cursor: pointer; border: none; }
			.result-btn-primary { background: #4f46e5; color: #fff; }
			.result-btn-primary:hover { background: #4338ca; }
			.result-btn-secondary { background: #334155; color: #f1f5f9; }
			.result-btn-secondary:hover { background: #475569; }
			.json-toggle { color: #818cf8; cursor: pointer; font-size: 0.75rem; margin-top: 0.75rem; display: inline-block; }
			.json-pre { background: #0f172a; border-radius: 8px; padding: 0.75rem; overflow-x: auto; font-size: 0.6875rem; color: #94a3b8; margin-top: 0.5rem; max-height: 300px; display: none; }
			.json-pre.visible { display: block; }
			input[type="file"] { display: none; }
			@media (max-width: 768px) {
				.products { grid-template-columns: repeat(2, 1fr); }
			}
		</style>

		<div class="products">
			${products.map((p) => `
				<div class="product ${this.selectedProduct === p.id ? 'active' : ''}" data-product="${p.id}">
					<div class="product-icon">${p.icon}</div>
					<div class="product-name">${p.name}</div>
					<div class="product-desc">${p.desc}</div>
				</div>
			`).join("")}
		</div>

		<div class="upload-area ${this.imagePreview ? 'has-image' : ''}">
			${this.imagePreview
				? `<img class="preview-img" src="${this.imagePreview}" alt="Preview">`
				: `<div class="upload-label">Click or drag to upload artwork (PNG, JPG, SVG)</div>`}
			<input type="file" accept="image/*">
		</div>

		<input class="title-input" type="text" placeholder="Design title" value="${this.esc(this.designTitle)}">

		<button class="generate-btn" ${!this.imageFile || this.generating ? 'disabled' : ''}>
			${this.generating ? 'Generating...' : 'Generate Print-Ready Files'}
		</button>

		${this.error ? `<div class="error">${this.esc(this.error)}</div>` : ""}

		${this.artifact ? `
		<div class="result">
			<h3 class="result-title">${this.esc(this.artifact.payload?.title || this.artifact.title || "Artifact")}</h3>
			<div class="result-meta">
				${this.esc(this.artifact.spec?.product_type || "")} &bull;
				${this.artifact.spec?.dimensions?.width_mm}x${this.artifact.spec?.dimensions?.height_mm}mm &bull;
				${this.artifact.spec?.dpi}dpi
			</div>
			<div class="result-actions">
				${Object.entries(this.artifact.render_targets || {}).map(([key, target]: [string, any]) => `
					<a class="result-btn result-btn-primary" href="${target.url}" target="_blank">Download ${target.format.toUpperCase()}</a>
				`).join("")}
				<button class="result-btn result-btn-secondary" data-action="copy-json">Copy Artifact JSON</button>
			</div>
			<span class="json-toggle">Show artifact envelope</span>
			<pre class="json-pre">${this.esc(JSON.stringify(this.artifact, null, 2))}</pre>
		</div>` : ""}
		`;

		// Event listeners
		this.shadow.querySelectorAll(".product").forEach((el) => {
			el.addEventListener("click", () => {
				this.selectedProduct = (el as HTMLElement).dataset.product || "sticker";
				this.render();
			});
		});

		const uploadArea = this.shadow.querySelector(".upload-area");
		const fileInput = this.shadow.querySelector('input[type="file"]') as HTMLInputElement;
		uploadArea?.addEventListener("click", () => fileInput?.click());
		fileInput?.addEventListener("change", () => {
			const file = fileInput.files?.[0];
			if (file) {
				this.imageFile = file;
				this.imagePreview = URL.createObjectURL(file);
				this.render();
			}
		});

		this.shadow.querySelector(".title-input")?.addEventListener("input", (e) => {
			this.designTitle = (e.target as HTMLInputElement).value;
		});

		this.shadow.querySelector(".generate-btn")?.addEventListener("click", () => this.generate());

		this.shadow.querySelector(".json-toggle")?.addEventListener("click", () => {
			const pre = this.shadow.querySelector(".json-pre");
			pre?.classList.toggle("visible");
		});

		this.shadow.querySelector('[data-action="copy-json"]')?.addEventListener("click", () => {
			navigator.clipboard.writeText(JSON.stringify(this.artifact, null, 2));
		});
	}

	private getDemoStyles(): string {
		return `
			:host { display: block; padding: 1.5rem; max-width: 960px; margin: 0 auto; }
			*, *::before, *::after { box-sizing: border-box; }

			/* Step bar */
			.steps-bar { display: flex; align-items: center; justify-content: center; gap: 0; margin-bottom: 2rem; }
			.step-dot { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; }
			.step-num { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 600; border: 2px solid #334155; color: #64748b; background: #1e293b; transition: all 0.2s; }
			.step-dot.active .step-num { border-color: #6366f1; color: #fff; background: #4f46e5; }
			.step-dot.current .step-num { box-shadow: 0 0 0 3px rgba(99,102,241,0.3); }
			.step-label { font-size: 0.6875rem; color: #64748b; }
			.step-dot.active .step-label { color: #a5b4fc; }
			.step-line { width: 40px; height: 2px; background: #334155; margin: 0 0.5rem; margin-bottom: 1rem; }

			/* Product grid */
			.products { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.75rem; margin-bottom: 1.5rem; }
			.product { padding: 0.875rem 0.5rem; border-radius: 12px; border: 2px solid #334155; background: #1e293b; cursor: pointer; text-align: center; transition: all 0.15s; }
			.product:hover { border-color: #475569; }
			.product.active { border-color: #6366f1; background: rgba(99,102,241,0.1); }
			.product-icon { margin-bottom: 0.375rem; display: flex; justify-content: center; }
			.product-name { color: #f1f5f9; font-weight: 600; font-size: 0.8125rem; }
			.product-specs { color: #64748b; font-size: 0.6875rem; margin-top: 0.125rem; }
			.product-cost { color: #94a3b8; font-size: 0.75rem; margin-top: 0.25rem; }

			/* Badges */
			.badge { display: inline-block; padding: 0.125rem 0.5rem; border-radius: 999px; font-size: 0.625rem; font-weight: 600; margin-top: 0.375rem; }
			.badge-printful { background: rgba(56,189,248,0.15); color: #38bdf8; }
			.badge-local { background: rgba(34,197,94,0.15); color: #4ade80; }
			.badge-cosmo { background: rgba(34,197,94,0.15); color: #4ade80; }
			.badge-global { background: rgba(56,189,248,0.15); color: #38bdf8; }
			.badge-ok { background: rgba(34,197,94,0.15); color: #4ade80; padding: 0.25rem 0.75rem; font-size: 0.75rem; }

			/* Options */
			.option-row { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
			.option-label { color: #94a3b8; font-size: 0.8125rem; font-weight: 500; min-width: 40px; }
			.pills { display: flex; gap: 0.375rem; flex-wrap: wrap; }
			.pill { padding: 0.375rem 0.75rem; border-radius: 999px; border: 1px solid #334155; background: #1e293b; color: #94a3b8; font-size: 0.75rem; cursor: pointer; transition: all 0.15s; }
			.pill:hover { border-color: #475569; color: #f1f5f9; }
			.pill.active { border-color: #6366f1; background: rgba(99,102,241,0.15); color: #fff; }
			.color-swatches { display: flex; gap: 0.5rem; }
			.swatch { width: 28px; height: 28px; border-radius: 50%; border: 2px solid #334155; cursor: pointer; transition: all 0.15s; }
			.swatch:hover { border-color: #475569; }
			.swatch.active { border-color: #6366f1; box-shadow: 0 0 0 3px rgba(99,102,241,0.3); }

			/* Mockup */
			.mockup-area { display: flex; gap: 1.5rem; align-items: center; background: #1e293b; border: 1px solid #334155; border-radius: 12px; padding: 1.5rem; margin-bottom: 1.5rem; }
			.mockup-svg { flex-shrink: 0; }
			.mockup-svg svg { width: 180px; height: auto; }
			.mockup-info { flex: 1; }
			.mockup-title { color: #f1f5f9; font-weight: 600; font-size: 1rem; margin: 0 0 0.25rem; }
			.mockup-meta { color: #94a3b8; font-size: 0.8125rem; margin-bottom: 0.75rem; }

			/* Buttons */
			.btn { padding: 0.625rem 1.25rem; border-radius: 8px; font-size: 0.875rem; font-weight: 600; cursor: pointer; border: none; text-decoration: none; display: inline-block; transition: all 0.15s; }
			.btn-primary { background: #4f46e5; color: #fff; }
			.btn-primary:hover { background: #4338ca; }
			.btn-secondary { background: #334155; color: #f1f5f9; }
			.btn-secondary:hover { background: #475569; }
			.generate-row { text-align: center; margin-bottom: 1.5rem; }

			/* Step sections */
			.step-section { margin-bottom: 1.5rem; }
			.step-section:not(.visible) { display: none; }

			/* Progress bar */
			.progress-bar { height: 6px; background: #1e293b; border-radius: 3px; overflow: hidden; margin-bottom: 0.5rem; }
			.progress-fill { height: 100%; background: linear-gradient(90deg, #6366f1, #818cf8); border-radius: 3px; transition: width 0.3s ease; }
			.progress-steps { display: flex; justify-content: space-between; margin-bottom: 1.5rem; }
			.prog-label { font-size: 0.6875rem; color: #475569; transition: color 0.2s; }
			.prog-label.active { color: #818cf8; font-weight: 600; }
			.prog-label.done { color: #4ade80; }

			/* Artifact card */
			.artifact-card { background: #1e293b; border: 1px solid #334155; border-radius: 12px; padding: 1.25rem; margin-bottom: 1rem; }
			.artifact-heading { color: #f1f5f9; font-weight: 600; font-size: 0.9375rem; margin: 0 0 0.75rem; }
			.artifact-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem 1rem; margin-bottom: 0.75rem; }
			.artifact-field { display: flex; flex-direction: column; }
			.af-label { color: #64748b; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.05em; }
			.af-value { color: #e2e8f0; font-size: 0.8125rem; }
			.artifact-targets { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
			.target-chip { background: rgba(99,102,241,0.1); color: #a5b4fc; padding: 0.25rem 0.625rem; border-radius: 6px; font-size: 0.6875rem; }
			.artifact-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
			.action-chip { background: #0f172a; color: #94a3b8; padding: 0.25rem 0.625rem; border-radius: 6px; font-size: 0.6875rem; border: 1px solid #334155; }

			/* Provider table */
			.provider-section { margin-bottom: 1rem; }
			.provider-heading { color: #f1f5f9; font-weight: 600; font-size: 0.9375rem; margin: 0 0 0.75rem; }
			.buyer-loc { color: #64748b; font-weight: 400; font-size: 0.75rem; }
			.provider-table { background: #1e293b; border: 1px solid #334155; border-radius: 12px; overflow: hidden; }
			.pt-header, .pt-row { display: grid; grid-template-columns: 2fr 1fr 1fr 1.2fr 0.8fr 1fr; padding: 0.625rem 1rem; font-size: 0.8125rem; align-items: center; }
			.pt-header { background: #0f172a; color: #64748b; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600; }
			.pt-row { color: #e2e8f0; border-top: 1px solid #1e293b; }
			.pt-row.nearest { background: rgba(99,102,241,0.05); border-left: 3px solid #6366f1; }
			.pt-name { font-weight: 500; }
			.pt-cost { color: #4ade80; font-weight: 600; }

			/* Split bar */
			.split-section { margin-bottom: 1.5rem; }
			.split-heading { color: #94a3b8; font-size: 0.8125rem; font-weight: 500; margin: 0 0 0.5rem; }
			.split-total { color: #64748b; font-weight: 400; }
			.split-bar { display: flex; height: 32px; border-radius: 8px; overflow: hidden; font-size: 0.6875rem; font-weight: 600; }
			.split-seg { display: flex; align-items: center; justify-content: center; gap: 0.25rem; color: #fff; }
			.split-provider { background: #16a34a; }
			.split-creator { background: #4f46e5; }
			.split-community { background: #d97706; }
			.split-amt { opacity: 0.85; }
			.split-legend { text-align: right; margin-top: 0.25rem; }
			.split-legend span { color: #64748b; font-size: 0.6875rem; }

			/* Pipeline */
			.pipeline-heading { color: #f1f5f9; font-weight: 600; font-size: 0.9375rem; margin: 0 0 1rem; text-align: center; }
			.pipeline { display: flex; align-items: center; justify-content: center; gap: 0; flex-wrap: wrap; margin-bottom: 1.5rem; }
			.pipe-node { display: flex; flex-direction: column; align-items: center; gap: 0.25rem; padding: 0.75rem; background: #1e293b; border: 1px solid #334155; border-radius: 10px; position: relative; min-width: 90px; }
			.pipe-node.done { border-color: #22c55e; }
			.pipe-icon { display: flex; align-items: center; justify-content: center; }
			.pipe-label { color: #e2e8f0; font-size: 0.6875rem; font-weight: 500; text-align: center; }
			.pipe-check { position: absolute; top: -6px; right: -6px; background: #16a34a; color: #fff; width: 16px; height: 16px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.5625rem; }
			.pipe-arrow { color: #475569; font-size: 1.25rem; margin: 0 0.25rem; margin-bottom: 0.75rem; }

			/* Pipeline actions */
			.pipeline-actions { display: flex; gap: 0.75rem; justify-content: center; margin-bottom: 1rem; }

			/* JSON */
			.json-pre { background: #0f172a; border: 1px solid #334155; border-radius: 8px; padding: 0.75rem; overflow-x: auto; font-size: 0.6875rem; color: #94a3b8; max-height: 300px; display: none; white-space: pre-wrap; word-break: break-all; }
			.json-pre.visible { display: block; }

			@media (max-width: 768px) {
				.products { grid-template-columns: repeat(2, 1fr); }
				.mockup-area { flex-direction: column; text-align: center; }
				.pt-header, .pt-row { grid-template-columns: 1.5fr 0.8fr 0.8fr 1fr 0.7fr 0.8fr; font-size: 0.6875rem; padding: 0.5rem; }
				.artifact-grid { grid-template-columns: repeat(2, 1fr); }
				.pipeline { gap: 0.25rem; }
				.pipe-node { min-width: 70px; padding: 0.5rem; }
				.pipe-label { font-size: 0.5625rem; }
			}
		`;
	}

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

customElements.define("folk-swag-designer", FolkSwagDesigner);
