/**
 * folk-gov-threshold — Numeric Progress Gate
 *
 * Tracks contributions toward a target value. Shows a progress bar,
 * turns green when target is met. Accepts contributions via input port
 * or direct UI. Target can be dynamically set via knob input port.
 */

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

const HEADER_COLOR = "#0891b2";

interface Contribution {
	who: string;
	amount: number;
	timestamp: number;
}

const styles = css`
	:host {
		background: var(--rs-bg-surface, #1e293b);
		border-radius: 10px;
		box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
		min-width: 220px;
		min-height: 100px;
		overflow: hidden;
	}

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

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

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

	.body {
		display: flex;
		flex-direction: column;
		padding: 12px;
		gap: 8px;
	}

	.title-input {
		background: transparent;
		border: none;
		color: var(--rs-text-primary, #e2e8f0);
		font-size: 13px;
		font-weight: 600;
		width: 100%;
		outline: none;
	}

	.title-input::placeholder {
		color: var(--rs-text-muted, #64748b);
	}

	.target-row {
		display: flex;
		align-items: center;
		gap: 6px;
		font-size: 11px;
		color: var(--rs-text-muted, #94a3b8);
	}

	.target-input, .unit-input {
		background: rgba(255, 255, 255, 0.06);
		border: 1px solid rgba(255, 255, 255, 0.1);
		border-radius: 4px;
		color: var(--rs-text-primary, #e2e8f0);
		font-size: 11px;
		padding: 2px 6px;
		outline: none;
	}

	.target-input {
		width: 60px;
		text-align: right;
	}

	.unit-input {
		width: 50px;
	}

	.progress-wrap {
		position: relative;
		height: 20px;
		background: rgba(255, 255, 255, 0.08);
		border-radius: 10px;
		overflow: hidden;
	}

	.progress-bar {
		height: 100%;
		border-radius: 10px;
		transition: width 0.3s, background 0.3s;
		background: ${HEADER_COLOR};
	}

	.progress-bar.complete {
		background: #22c55e;
		box-shadow: 0 0 8px rgba(34, 197, 94, 0.4);
	}

	.progress-label {
		position: absolute;
		inset: 0;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 10px;
		font-weight: 600;
		color: white;
		text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
	}

	.contribute-row {
		display: flex;
		gap: 4px;
	}

	.contrib-name, .contrib-amount {
		background: rgba(255, 255, 255, 0.06);
		border: 1px solid rgba(255, 255, 255, 0.1);
		border-radius: 4px;
		color: var(--rs-text-primary, #e2e8f0);
		font-size: 11px;
		padding: 3px 6px;
		outline: none;
	}

	.contrib-name {
		flex: 1;
	}

	.contrib-amount {
		width: 50px;
		text-align: right;
	}

	.contrib-btn {
		background: ${HEADER_COLOR};
		border: none;
		color: white;
		border-radius: 4px;
		padding: 3px 8px;
		font-size: 11px;
		cursor: pointer;
		font-weight: 600;
	}

	.contrib-btn:hover {
		opacity: 0.85;
	}

	.contributions-list {
		max-height: 80px;
		overflow-y: auto;
		font-size: 10px;
		color: var(--rs-text-muted, #94a3b8);
	}

	.contrib-item {
		display: flex;
		justify-content: space-between;
		padding: 2px 0;
		border-bottom: 1px solid rgba(255, 255, 255, 0.05);
	}

	.status-label {
		font-size: 10px;
		font-weight: 500;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		text-align: center;
	}

	.status-label.satisfied {
		color: #22c55e;
	}

	.status-label.waiting {
		color: #f59e0b;
	}
`;

declare global {
	interface HTMLElementTagNameMap {
		"folk-gov-threshold": FolkGovThreshold;
	}
}

export class FolkGovThreshold extends FolkShape {
	static override tagName = "folk-gov-threshold";

	static override portDescriptors: PortDescriptor[] = [
		{ name: "contribution-in", type: "json", direction: "input" },
		{ name: "target-in", type: "number", direction: "input" },
		{ name: "gate-out", type: "json", direction: "output" },
	];

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

	#title = "Threshold";
	#target = 100;
	#unit = "$";
	#contributions: Contribution[] = [];

	// DOM refs
	#titleEl!: HTMLInputElement;
	#targetEl!: HTMLInputElement;
	#unitEl!: HTMLInputElement;
	#progressBar!: HTMLElement;
	#progressLabel!: HTMLElement;
	#contribList!: HTMLElement;
	#statusEl!: HTMLElement;
	#contribNameEl!: HTMLInputElement;
	#contribAmountEl!: HTMLInputElement;

	get title() { return this.#title; }
	set title(v: string) {
		this.#title = v;
		if (this.#titleEl) this.#titleEl.value = v;
	}

	get target() { return this.#target; }
	set target(v: number) {
		this.#target = v;
		if (this.#targetEl) this.#targetEl.value = String(v);
		this.#updateVisuals();
		this.#emitPort();
	}

	get unit() { return this.#unit; }
	set unit(v: string) {
		this.#unit = v;
		if (this.#unitEl) this.#unitEl.value = v;
		this.#updateVisuals();
	}

	get contributions(): Contribution[] { return [...this.#contributions]; }
	set contributions(v: Contribution[]) {
		this.#contributions = v;
		this.#updateVisuals();
		this.#emitPort();
	}

	get #current(): number {
		return this.#contributions.reduce((sum, c) => sum + c.amount, 0);
	}

	get #percentage(): number {
		return this.#target > 0 ? Math.min(100, (this.#current / this.#target) * 100) : 0;
	}

	get #isSatisfied(): boolean {
		return this.#current >= this.#target;
	}

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

		const wrapper = document.createElement("div");
		wrapper.style.cssText = "width:100%;height:100%;display:flex;flex-direction:column;";
		wrapper.innerHTML = html`
			<div class="header" data-drag>
				<span class="header-title">📊 Threshold</span>
				<span class="header-actions">
					<button class="close-btn">&times;</button>
				</span>
			</div>
			<div class="body">
				<input class="title-input" type="text" placeholder="Threshold title..." />
				<div class="target-row">
					<span>Target:</span>
					<input class="target-input" type="number" min="0" />
					<input class="unit-input" type="text" placeholder="unit" />
				</div>
				<div class="progress-wrap">
					<div class="progress-bar" style="width: 0%"></div>
					<div class="progress-label">0 / 100</div>
				</div>
				<div class="contribute-row">
					<input class="contrib-name" type="text" placeholder="Name" />
					<input class="contrib-amount" type="number" placeholder="0" min="0" />
					<button class="contrib-btn">+</button>
				</div>
				<div class="contributions-list"></div>
				<span class="status-label waiting">WAITING</span>
			</div>
		`;

		const slot = root.querySelector("slot");
		const container = slot?.parentElement as HTMLElement;
		if (container) container.replaceWith(wrapper);

		// Cache refs
		this.#titleEl = wrapper.querySelector(".title-input") as HTMLInputElement;
		this.#targetEl = wrapper.querySelector(".target-input") as HTMLInputElement;
		this.#unitEl = wrapper.querySelector(".unit-input") as HTMLInputElement;
		this.#progressBar = wrapper.querySelector(".progress-bar") as HTMLElement;
		this.#progressLabel = wrapper.querySelector(".progress-label") as HTMLElement;
		this.#contribList = wrapper.querySelector(".contributions-list") as HTMLElement;
		this.#statusEl = wrapper.querySelector(".status-label") as HTMLElement;
		this.#contribNameEl = wrapper.querySelector(".contrib-name") as HTMLInputElement;
		this.#contribAmountEl = wrapper.querySelector(".contrib-amount") as HTMLInputElement;

		// Set initial values
		this.#titleEl.value = this.#title;
		this.#targetEl.value = String(this.#target);
		this.#unitEl.value = this.#unit;
		this.#updateVisuals();

		// Wire events
		this.#titleEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#title = this.#titleEl.value;
			this.dispatchEvent(new CustomEvent("content-change"));
		});

		this.#targetEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#target = parseFloat(this.#targetEl.value) || 0;
			this.#updateVisuals();
			this.#emitPort();
			this.dispatchEvent(new CustomEvent("content-change"));
		});

		this.#unitEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#unit = this.#unitEl.value;
			this.#updateVisuals();
			this.dispatchEvent(new CustomEvent("content-change"));
		});

		wrapper.querySelector(".contrib-btn")!.addEventListener("click", (e) => {
			e.stopPropagation();
			const who = this.#contribNameEl.value.trim() || "anonymous";
			const amount = parseFloat(this.#contribAmountEl.value) || 0;
			if (amount <= 0) return;
			this.#contributions.push({ who, amount, timestamp: Date.now() });
			this.#contribNameEl.value = "";
			this.#contribAmountEl.value = "";
			this.#updateVisuals();
			this.#emitPort();
			this.dispatchEvent(new CustomEvent("content-change"));
		});

		wrapper.querySelector(".close-btn")!.addEventListener("click", (e) => {
			e.stopPropagation();
			this.dispatchEvent(new CustomEvent("close"));
		});

		// Prevent drag on inputs
		for (const el of wrapper.querySelectorAll("input, button")) {
			el.addEventListener("pointerdown", (e) => e.stopPropagation());
		}

		// Handle input ports
		this.addEventListener("port-value-changed", ((e: CustomEvent) => {
			const { name, value } = e.detail;
			if (name === "contribution-in" && value && typeof value === "object") {
				const c = value as any;
				this.#contributions.push({
					who: c.who || c.memberName || "anonymous",
					amount: c.amount || c.hours || 0,
					timestamp: c.timestamp || Date.now(),
				});
				this.#updateVisuals();
				this.#emitPort();
				this.dispatchEvent(new CustomEvent("content-change"));
			}
			if (name === "target-in" && typeof value === "number") {
				this.#target = value;
				if (this.#targetEl) this.#targetEl.value = String(value);
				this.#updateVisuals();
				this.#emitPort();
				this.dispatchEvent(new CustomEvent("content-change"));
			}
		}) as EventListener);

		return root;
	}

	#updateVisuals() {
		if (!this.#progressBar) return;
		const pct = this.#percentage;
		const current = this.#current;
		const satisfied = this.#isSatisfied;

		this.#progressBar.style.width = `${pct}%`;
		this.#progressBar.classList.toggle("complete", satisfied);
		this.#progressLabel.textContent = `${current} / ${this.#target} ${this.#unit}`;

		if (this.#statusEl) {
			this.#statusEl.textContent = satisfied ? "SATISFIED" : "WAITING";
			this.#statusEl.className = `status-label ${satisfied ? "satisfied" : "waiting"}`;
		}

		// Render contributions list
		if (this.#contribList) {
			this.#contribList.innerHTML = this.#contributions.map(c =>
				`<div class="contrib-item"><span>${c.who}</span><span>${c.amount} ${this.#unit}</span></div>`
			).join("");
		}
	}

	#emitPort() {
		this.setPortValue("gate-out", {
			satisfied: this.#isSatisfied,
			current: this.#current,
			target: this.#target,
			percentage: this.#percentage,
		});
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-gov-threshold",
			title: this.#title,
			target: this.#target,
			unit: this.#unit,
			contributions: this.#contributions,
		};
	}

	static override fromData(data: Record<string, any>): FolkGovThreshold {
		const shape = FolkShape.fromData.call(this, data) as FolkGovThreshold;
		if (data.title !== undefined) shape.title = data.title;
		if (data.target !== undefined) shape.target = data.target;
		if (data.unit !== undefined) shape.unit = data.unit;
		if (data.contributions !== undefined) shape.contributions = data.contributions;
		return shape;
	}

	override applyData(data: Record<string, any>): void {
		super.applyData(data);
		if (data.title !== undefined && data.title !== this.#title) this.title = data.title;
		if (data.target !== undefined && data.target !== this.#target) this.target = data.target;
		if (data.unit !== undefined && data.unit !== this.#unit) this.unit = data.unit;
		if (data.contributions !== undefined) this.contributions = data.contributions;
	}
}
