/**
 * folk-gov-amendment — Circuit Modification Proposal
 *
 * References a target shape to modify, contains proposed replacement data.
 * Built-in approval mechanism (majority/unanimous/single) with inline voter list.
 * Shows a "Before → After" diff view. On approval, dispatches gov-amendment-apply
 * event to replace the target shape while preserving its ID.
 */

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

const HEADER_COLOR = "#be185d";

type ApprovalMode = "single" | "majority" | "unanimous";

interface Vote {
	voter: string;
	approve: boolean;
	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: 280px;
		min-height: 200px;
		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;
		overflow-y: auto;
		max-height: calc(100% - 36px);
	}

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

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

	.field-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: 3px 6px;
		outline: none;
		flex: 1;
	}

	.mode-select {
		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;
	}

	.diff-section {
		display: flex;
		flex-direction: column;
		gap: 4px;
		margin-top: 4px;
	}

	.diff-label {
		font-size: 10px;
		font-weight: 600;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		color: var(--rs-text-muted, #64748b);
	}

	.diff-box {
		background: rgba(255, 255, 255, 0.04);
		border: 1px solid rgba(255, 255, 255, 0.08);
		border-radius: 4px;
		padding: 6px 8px;
		font-size: 10px;
		font-family: monospace;
		color: var(--rs-text-secondary, #94a3b8);
		max-height: 60px;
		overflow-y: auto;
		white-space: pre-wrap;
	}

	.diff-box.before {
		border-left: 3px solid #ef4444;
	}

	.diff-box.after {
		border-left: 3px solid #22c55e;
	}

	.diff-arrow {
		text-align: center;
		font-size: 14px;
		color: var(--rs-text-muted, #475569);
	}

	.desc-textarea {
		background: rgba(255, 255, 255, 0.04);
		border: 1px solid rgba(255, 255, 255, 0.08);
		border-radius: 4px;
		color: var(--rs-text-secondary, #cbd5e1);
		font-size: 11px;
		padding: 6px 8px;
		outline: none;
		resize: none;
		min-height: 36px;
	}

	.desc-textarea::placeholder {
		color: var(--rs-text-muted, #475569);
	}

	.voters-section {
		display: flex;
		flex-direction: column;
		gap: 4px;
	}

	.voter-row {
		display: flex;
		align-items: center;
		justify-content: space-between;
		font-size: 11px;
		padding: 3px 6px;
		border-radius: 4px;
		background: rgba(255, 255, 255, 0.03);
	}

	.voter-name {
		color: var(--rs-text-primary, #e2e8f0);
	}

	.vote-badge {
		font-size: 10px;
		font-weight: 600;
		padding: 1px 6px;
		border-radius: 3px;
	}

	.vote-badge.approve {
		background: rgba(34, 197, 94, 0.2);
		color: #22c55e;
	}

	.vote-badge.reject {
		background: rgba(239, 68, 68, 0.2);
		color: #ef4444;
	}

	.vote-actions {
		display: flex;
		gap: 4px;
		margin-top: 4px;
	}

	.vote-name-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: 3px 6px;
		outline: none;
		flex: 1;
	}

	.vote-btn {
		border: none;
		border-radius: 4px;
		padding: 3px 8px;
		font-size: 11px;
		font-weight: 600;
		cursor: pointer;
	}

	.vote-btn.approve {
		background: #22c55e;
		color: white;
	}

	.vote-btn.reject {
		background: #ef4444;
		color: white;
	}

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

	.apply-btn {
		background: ${HEADER_COLOR};
		border: none;
		color: white;
		border-radius: 6px;
		padding: 6px 12px;
		font-size: 12px;
		font-weight: 600;
		cursor: pointer;
		text-align: center;
		margin-top: 4px;
	}

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

	.apply-btn:disabled {
		opacity: 0.4;
		cursor: not-allowed;
	}

	.status-badge {
		display: inline-block;
		font-size: 10px;
		font-weight: 600;
		text-transform: uppercase;
		letter-spacing: 0.5px;
		padding: 2px 8px;
		border-radius: 4px;
		text-align: center;
	}

	.status-badge.pending {
		background: rgba(245, 158, 11, 0.2);
		color: #f59e0b;
	}

	.status-badge.approved {
		background: rgba(34, 197, 94, 0.2);
		color: #22c55e;
	}

	.status-badge.rejected {
		background: rgba(239, 68, 68, 0.2);
		color: #ef4444;
	}

	.status-badge.applied {
		background: rgba(29, 78, 216, 0.2);
		color: #60a5fa;
	}
`;

declare global {
	interface HTMLElementTagNameMap {
		"folk-gov-amendment": FolkGovAmendment;
	}
}

export class FolkGovAmendment extends FolkShape {
	static override tagName = "folk-gov-amendment";

	static override portDescriptors: PortDescriptor[] = [
		{ name: "approval-in", type: "json", direction: "input" },
		{ name: "amendment-out", type: "json", direction: "output" },
		{ 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 = "Amendment";
	#targetShapeId = "";
	#replacementType = "folk-gov-binary"; // what to replace with
	#replacementData: Record<string, any> = {};
	#approvalMode: ApprovalMode = "single";
	#votes: Vote[] = [];
	#amendmentStatus: "pending" | "approved" | "rejected" | "applied" = "pending";
	#description = "";

	// DOM refs
	#titleEl!: HTMLInputElement;
	#targetEl!: HTMLInputElement;
	#replTypeEl!: HTMLInputElement;
	#modeEl!: HTMLSelectElement;
	#descEl!: HTMLTextAreaElement;
	#votersEl!: HTMLElement;
	#statusEl!: HTMLElement;
	#applyBtn!: HTMLButtonElement;
	#beforeBox!: HTMLElement;
	#voteNameEl!: HTMLInputElement;

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

	get targetShapeId() { return this.#targetShapeId; }
	set targetShapeId(v: string) {
		this.#targetShapeId = v;
		if (this.#targetEl) this.#targetEl.value = v;
		this.#updateDiff();
	}

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

	get replacementData() { return this.#replacementData; }
	set replacementData(v: Record<string, any>) { this.#replacementData = v; }

	get approvalMode(): ApprovalMode { return this.#approvalMode; }
	set approvalMode(v: ApprovalMode) {
		this.#approvalMode = v;
		if (this.#modeEl) this.#modeEl.value = v;
	}

	get votes() { return [...this.#votes]; }
	set votes(v: Vote[]) {
		this.#votes = v;
		this.#renderVoters();
		this.#checkApproval();
	}

	get amendmentStatus() { return this.#amendmentStatus; }
	set amendmentStatus(v: "pending" | "approved" | "rejected" | "applied") {
		this.#amendmentStatus = v;
		this.#updateStatusBadge();
	}

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

	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">📝 Amendment</span>
				<span class="header-actions">
					<button class="close-btn">&times;</button>
				</span>
			</div>
			<div class="body">
				<input class="title-input" type="text" placeholder="Amendment title..." />
				<div class="field-row">
					<span>Target:</span>
					<input class="field-input target-id" type="text" placeholder="shape ID to replace" />
				</div>
				<div class="field-row">
					<span>Replace with:</span>
					<input class="field-input repl-type" type="text" placeholder="folk-gov-binary" />
				</div>
				<div class="field-row">
					<span>Approval:</span>
					<select class="mode-select">
						<option value="single">Single</option>
						<option value="majority">Majority</option>
						<option value="unanimous">Unanimous</option>
					</select>
				</div>
				<textarea class="desc-textarea" placeholder="Describe what this amendment changes..." rows="2"></textarea>
				<div class="diff-section">
					<span class="diff-label">Before</span>
					<div class="diff-box before"></div>
					<div class="diff-arrow">↓</div>
					<span class="diff-label">After</span>
					<div class="diff-box after"></div>
				</div>
				<div class="voters-section"></div>
				<div class="vote-actions">
					<input class="vote-name-input" type="text" placeholder="Your name" />
					<button class="vote-btn approve">✓</button>
					<button class="vote-btn reject">✗</button>
				</div>
				<span class="status-badge pending">PENDING</span>
				<button class="apply-btn" disabled>Apply Amendment</button>
			</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-id") as HTMLInputElement;
		this.#replTypeEl = wrapper.querySelector(".repl-type") as HTMLInputElement;
		this.#modeEl = wrapper.querySelector(".mode-select") as HTMLSelectElement;
		this.#descEl = wrapper.querySelector(".desc-textarea") as HTMLTextAreaElement;
		this.#votersEl = wrapper.querySelector(".voters-section") as HTMLElement;
		this.#statusEl = wrapper.querySelector(".status-badge") as HTMLElement;
		this.#applyBtn = wrapper.querySelector(".apply-btn") as HTMLButtonElement;
		this.#beforeBox = wrapper.querySelector(".diff-box.before") as HTMLElement;
		this.#voteNameEl = wrapper.querySelector(".vote-name-input") as HTMLInputElement;
		const afterBox = wrapper.querySelector(".diff-box.after") as HTMLElement;

		// Set initial values
		this.#titleEl.value = this.#title;
		this.#targetEl.value = this.#targetShapeId;
		this.#replTypeEl.value = this.#replacementType;
		this.#modeEl.value = this.#approvalMode;
		this.#descEl.value = this.#description;
		afterBox.textContent = this.#replacementType;
		this.#updateDiff();
		this.#renderVoters();
		this.#updateStatusBadge();

		// Wire events
		const onChange = () => this.dispatchEvent(new CustomEvent("content-change"));

		this.#titleEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#title = this.#titleEl.value;
			onChange();
		});

		this.#targetEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#targetShapeId = this.#targetEl.value;
			this.#updateDiff();
			onChange();
		});

		this.#replTypeEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#replacementType = this.#replTypeEl.value;
			afterBox.textContent = `type: ${this.#replacementType}`;
			onChange();
		});

		this.#modeEl.addEventListener("change", (e) => {
			e.stopPropagation();
			this.#approvalMode = this.#modeEl.value as ApprovalMode;
			this.#checkApproval();
			onChange();
		});

		this.#descEl.addEventListener("input", (e) => {
			e.stopPropagation();
			this.#description = this.#descEl.value;
			onChange();
		});

		// Vote buttons
		wrapper.querySelector(".vote-btn.approve")!.addEventListener("click", (e) => {
			e.stopPropagation();
			this.#castVote(true);
			onChange();
		});

		wrapper.querySelector(".vote-btn.reject")!.addEventListener("click", (e) => {
			e.stopPropagation();
			this.#castVote(false);
			onChange();
		});

		// Apply button
		this.#applyBtn.addEventListener("click", (e) => {
			e.stopPropagation();
			this.#applyAmendment();
			onChange();
		});

		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, textarea, select, button")) {
			el.addEventListener("pointerdown", (e) => e.stopPropagation());
		}

		// Handle approval-in port
		this.addEventListener("port-value-changed", ((e: CustomEvent) => {
			const { name, value } = e.detail;
			if (name === "approval-in" && value && typeof value === "object") {
				const v = value as any;
				if (v.voter && v.approve !== undefined) {
					this.#votes.push({
						voter: v.voter,
						approve: !!v.approve,
						timestamp: v.timestamp || Date.now(),
					});
					this.#renderVoters();
					this.#checkApproval();
					onChange();
				}
			}
		}) as EventListener);

		return root;
	}

	#updateDiff() {
		if (!this.#beforeBox) return;
		if (!this.#targetShapeId) {
			this.#beforeBox.textContent = "(no target selected)";
			return;
		}
		const target = document.getElementById(this.#targetShapeId) as any;
		if (!target) {
			this.#beforeBox.textContent = `(shape "${this.#targetShapeId}" not found)`;
			return;
		}
		const data = target.toJSON?.() || {};
		this.#beforeBox.textContent = `type: ${data.type || target.tagName}\ntitle: ${data.title || "—"}`;
	}

	#castVote(approve: boolean) {
		const voter = this.#voteNameEl?.value.trim() || "anonymous";
		// Prevent duplicate votes from same voter
		const existing = this.#votes.findIndex(v => v.voter === voter);
		if (existing >= 0) {
			this.#votes[existing] = { voter, approve, timestamp: Date.now() };
		} else {
			this.#votes.push({ voter, approve, timestamp: Date.now() });
		}
		if (this.#voteNameEl) this.#voteNameEl.value = "";
		this.#renderVoters();
		this.#checkApproval();
	}

	#renderVoters() {
		if (!this.#votersEl) return;
		this.#votersEl.innerHTML = this.#votes.map(v => {
			const badge = v.approve
				? `<span class="vote-badge approve">YES</span>`
				: `<span class="vote-badge reject">NO</span>`;
			return `<div class="voter-row"><span class="voter-name">${v.voter}</span>${badge}</div>`;
		}).join("");
	}

	#checkApproval() {
		if (this.#amendmentStatus === "applied") return;

		const approvals = this.#votes.filter(v => v.approve).length;
		const rejections = this.#votes.filter(v => !v.approve).length;
		const total = this.#votes.length;

		let approved = false;
		if (this.#approvalMode === "single") {
			approved = approvals >= 1;
		} else if (this.#approvalMode === "majority") {
			approved = total > 0 && approvals > total / 2;
		} else if (this.#approvalMode === "unanimous") {
			approved = total > 0 && rejections === 0;
		}

		if (approved) {
			this.#amendmentStatus = "approved";
		} else if (total > 0 && this.#approvalMode === "unanimous" && rejections > 0) {
			this.#amendmentStatus = "rejected";
		} else {
			this.#amendmentStatus = "pending";
		}

		this.#updateStatusBadge();
		this.#emitPorts();
	}

	#updateStatusBadge() {
		if (!this.#statusEl || !this.#applyBtn) return;
		this.#statusEl.textContent = this.#amendmentStatus.toUpperCase();
		this.#statusEl.className = `status-badge ${this.#amendmentStatus}`;
		this.#applyBtn.disabled = this.#amendmentStatus !== "approved";
	}

	#applyAmendment() {
		if (this.#amendmentStatus !== "approved") return;
		if (!this.#targetShapeId) return;

		// Dispatch event for canvas to handle the shape replacement
		this.dispatchEvent(new CustomEvent("gov-amendment-apply", {
			bubbles: true,
			composed: true,
			detail: {
				targetShapeId: this.#targetShapeId,
				replacementType: this.#replacementType,
				replacementData: this.#replacementData,
				amendmentId: this.id,
			},
		}));

		this.#amendmentStatus = "applied";
		this.#updateStatusBadge();
		this.#emitPorts();
	}

	#emitPorts() {
		const data = {
			status: this.#amendmentStatus,
			targetShapeId: this.#targetShapeId,
			approved: this.#amendmentStatus === "approved" || this.#amendmentStatus === "applied",
		};
		this.setPortValue("amendment-out", data);
		this.setPortValue("gate-out", {
			satisfied: this.#amendmentStatus === "approved" || this.#amendmentStatus === "applied",
		});
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-gov-amendment",
			title: this.#title,
			targetShapeId: this.#targetShapeId,
			replacementType: this.#replacementType,
			replacementData: this.#replacementData,
			approvalMode: this.#approvalMode,
			votes: this.#votes,
			amendmentStatus: this.#amendmentStatus,
			description: this.#description,
		};
	}

	static override fromData(data: Record<string, any>): FolkGovAmendment {
		const shape = FolkShape.fromData.call(this, data) as FolkGovAmendment;
		if (data.title !== undefined) shape.title = data.title;
		if (data.targetShapeId !== undefined) shape.targetShapeId = data.targetShapeId;
		if (data.replacementType !== undefined) shape.replacementType = data.replacementType;
		if (data.replacementData !== undefined) shape.replacementData = data.replacementData;
		if (data.approvalMode !== undefined) shape.approvalMode = data.approvalMode;
		if (data.votes !== undefined) shape.votes = data.votes;
		if (data.amendmentStatus !== undefined) shape.amendmentStatus = data.amendmentStatus;
		if (data.description !== undefined) shape.description = data.description;
		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.targetShapeId !== undefined && data.targetShapeId !== this.#targetShapeId) this.targetShapeId = data.targetShapeId;
		if (data.replacementType !== undefined && data.replacementType !== this.#replacementType) this.replacementType = data.replacementType;
		if (data.replacementData !== undefined) this.replacementData = data.replacementData;
		if (data.approvalMode !== undefined && data.approvalMode !== this.#approvalMode) this.approvalMode = data.approvalMode;
		if (data.votes !== undefined) this.votes = data.votes;
		if (data.amendmentStatus !== undefined && data.amendmentStatus !== this.#amendmentStatus) this.amendmentStatus = data.amendmentStatus;
		if (data.description !== undefined && data.description !== this.#description) this.description = data.description;
	}
}
