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: 320px;
		min-height: 280px;
	}

	.header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 8px 12px;
		background: #6d28d9;
		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-title .symbol {
		opacity: 0.8;
		font-weight: 400;
		font-size: 11px;
	}

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

	.ledger-body {
		padding: 12px;
	}

	.summary-row {
		display: flex;
		justify-content: space-between;
		font-size: 12px;
		margin-bottom: 4px;
	}

	.summary-row .label {
		color: var(--rs-text-muted, #64748b);
	}

	.summary-row .value {
		font-weight: 600;
		color: var(--rs-text-primary, #e2e8f0);
	}

	.holder-list {
		max-height: 220px;
		overflow-y: auto;
		margin-top: 10px;
	}

	.holder-item {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 6px 8px;
		font-size: 12px;
		border-radius: 4px;
		margin-bottom: 3px;
		background: var(--rs-bg-surface-sunken, #0f172a);
	}

	.holder-item:hover {
		background: var(--rs-bg-hover, rgba(255, 255, 255, 0.05));
	}

	.holder-info {
		display: flex;
		align-items: center;
		gap: 6px;
	}

	.holder-icon {
		width: 20px;
		height: 20px;
		border-radius: 50%;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 10px;
		color: white;
		flex-shrink: 0;
	}

	.holder-name {
		color: var(--rs-text-primary, #e2e8f0);
		font-weight: 500;
	}

	.holder-memo {
		font-size: 9px;
		color: var(--rs-text-secondary, #94a3b8);
	}

	.holder-amount {
		font-weight: 600;
		color: #6d28d9;
		white-space: nowrap;
	}

	.escrow-badge {
		font-size: 9px;
		background: #fef3c7;
		color: #92400e;
		padding: 1px 5px;
		border-radius: 3px;
		margin-left: 4px;
	}

	.empty-state {
		text-align: center;
		padding: 16px;
		color: #94a3b8;
		font-size: 12px;
	}

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

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

	.issue-form input {
		flex: 1;
		padding: 6px 8px;
		border: 1px solid #e2e8f0;
		border-radius: 4px;
		font-size: 12px;
		outline: none;
	}

	.issue-form input:focus {
		border-color: #6d28d9;
	}

	.issue-form input.amount-input {
		width: 80px;
		flex: 0;
	}

	.issue-btn {
		padding: 6px 12px;
		background: #6d28d9;
		color: white;
		border: none;
		border-radius: 4px;
		font-size: 11px;
		font-weight: 600;
		cursor: pointer;
		white-space: nowrap;
	}

	.issue-btn:hover {
		background: #5b21b6;
	}

	.issue-btn:disabled {
		background: #cbd5e1;
		cursor: not-allowed;
	}
`;

export interface LedgerEntry {
	id: string;
	holder: string;
	holderLabel: string;
	amount: number;
	issuedAt: string;
	issuedBy: string;
	memo: string;
}

declare global {
	interface HTMLElementTagNameMap {
		"folk-token-ledger": FolkTokenLedger;
	}
}

export class FolkTokenLedger extends FolkShape {
	static override tagName = "folk-token-ledger";

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

	#mintId = "";
	#entries: LedgerEntry[] = [];

	#headerEl: HTMLElement | null = null;
	#summaryEl: HTMLElement | null = null;
	#listEl: HTMLElement | null = null;
	#issueBtnEl: HTMLButtonElement | null = null;

	get mintId() { return this.#mintId; }
	set mintId(v: string) {
		this.#mintId = v;
		this.#render();
	}

	get entries() { return this.#entries; }
	set entries(v: LedgerEntry[]) {
		this.#entries = v;
		this.#render();
		this.#updateLinkedMint();
		this.dispatchEvent(new CustomEvent("content-change"));
	}

	get totalIssued() {
		return this.#entries.reduce((sum, e) => sum + e.amount, 0);
	}

	addEntry(entry: LedgerEntry) {
		this.#entries.push(entry);
		this.#render();
		this.#updateLinkedMint();
		this.dispatchEvent(new CustomEvent("content-change"));
	}

	#getLinkedMint(): HTMLElement | null {
		if (!this.#mintId) return null;
		return document.getElementById(this.#mintId);
	}

	#getMintInfo(): { name: string; symbol: string; color: string; totalSupply: number } {
		const mint = this.#getLinkedMint() as any;
		if (mint) {
			return {
				name: mint.tokenName || "Token",
				symbol: mint.tokenSymbol || "TKN",
				color: mint.tokenColor || "#6d28d9",
				totalSupply: mint.totalSupply || 0,
			};
		}
		return { name: "Token", symbol: "TKN", color: "#6d28d9", totalSupply: 0 };
	}

	#updateLinkedMint() {
		const mint = this.#getLinkedMint() as any;
		if (mint && typeof mint.issuedSupply !== "undefined") {
			mint.issuedSupply = this.totalIssued;
		}
	}

	#isEmail(s: string): boolean {
		return s.includes("@") && !s.startsWith("did:");
	}

	#holderColor(holder: string): string {
		let hash = 0;
		for (let i = 0; i < holder.length; i++) {
			hash = ((hash << 5) - hash + holder.charCodeAt(i)) | 0;
		}
		const hue = Math.abs(hash) % 360;
		return `hsl(${hue}, 55%, 50%)`;
	}

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

		const wrapper = document.createElement("div");
		wrapper.innerHTML = html`
			<div class="header">
				<span class="header-title">
					<span>📜</span>
					<span class="name">Token Ledger</span>
					<span class="symbol"></span>
				</span>
				<div class="header-actions">
					<button class="close-btn" title="Close">×</button>
				</div>
			</div>
			<div class="ledger-body">
				<div class="summary"></div>
				<div class="holder-list"></div>
			</div>
			<div class="issue-form">
				<div class="issue-row">
					<input type="text" placeholder="Email or DID..." class="holder-input" />
					<input type="number" placeholder="Amt" class="amount-input" min="1" />
				</div>
				<div class="issue-row">
					<input type="text" placeholder="Memo (optional)" class="memo-input" />
					<button class="issue-btn">Issue</button>
				</div>
			</div>
		`;

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

		this.#headerEl = wrapper.querySelector(".header");
		this.#summaryEl = wrapper.querySelector(".summary");
		this.#listEl = wrapper.querySelector(".holder-list");

		const closeBtn = wrapper.querySelector(".close-btn") as HTMLButtonElement;
		const holderInput = wrapper.querySelector(".holder-input") as HTMLInputElement;
		const amountInput = wrapper.querySelector(".amount-input") as HTMLInputElement;
		const memoInput = wrapper.querySelector(".memo-input") as HTMLInputElement;
		this.#issueBtnEl = wrapper.querySelector(".issue-btn") as HTMLButtonElement;

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

		const stopProp = (e: Event) => e.stopPropagation();
		holderInput.addEventListener("click", stopProp);
		amountInput.addEventListener("click", stopProp);
		memoInput.addEventListener("click", stopProp);

		const issueToken = () => {
			const holder = holderInput.value.trim();
			const amount = Number(amountInput.value);
			const memo = memoInput.value.trim();

			if (!holder || !amount || amount <= 0) return;

			// Check supply
			const mintInfo = this.#getMintInfo();
			if (mintInfo.totalSupply > 0 && this.totalIssued + amount > mintInfo.totalSupply) {
				return; // Would exceed supply
			}

			const label = this.#isEmail(holder)
				? holder.split("@")[0]
				: holder.length > 16 ? `${holder.slice(0, 8)}...${holder.slice(-4)}` : holder;

			this.addEntry({
				id: `entry-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
				holder,
				holderLabel: label,
				amount,
				issuedAt: new Date().toISOString(),
				issuedBy: "",
				memo: memo || "Issued",
			});

			holderInput.value = "";
			amountInput.value = "";
			memoInput.value = "";
		};

		this.#issueBtnEl.addEventListener("click", (e) => {
			e.stopPropagation();
			issueToken();
		});

		holderInput.addEventListener("keydown", (e) => {
			if (e.key === "Enter") { e.stopPropagation(); issueToken(); }
		});
		amountInput.addEventListener("keydown", (e) => {
			if (e.key === "Enter") { e.stopPropagation(); issueToken(); }
		});
		memoInput.addEventListener("keydown", (e) => {
			if (e.key === "Enter") { e.stopPropagation(); issueToken(); }
		});

		this.#render();
		return root;
	}

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

	#render() {
		if (!this.#headerEl || !this.#summaryEl || !this.#listEl) return;

		const mintInfo = this.#getMintInfo();

		// Update header
		this.#headerEl.style.background = mintInfo.color;
		const nameEl = this.#headerEl.querySelector(".name");
		const symbolEl = this.#headerEl.querySelector(".symbol");
		if (nameEl) nameEl.textContent = `${mintInfo.name} Ledger`;
		if (symbolEl) symbolEl.textContent = mintInfo.symbol;

		// Update issue button color
		if (this.#issueBtnEl) {
			this.#issueBtnEl.style.background = mintInfo.color;
		}

		const totalIssued = this.totalIssued;
		const remaining = mintInfo.totalSupply > 0 ? mintInfo.totalSupply - totalIssued : 0;

		this.#summaryEl.innerHTML = `
			<div class="summary-row">
				<span class="label">Total Issued</span>
				<span class="value">${totalIssued.toLocaleString()} ${this.#escapeHtml(mintInfo.symbol)}</span>
			</div>
			${mintInfo.totalSupply > 0 ? `
			<div class="summary-row">
				<span class="label">Remaining</span>
				<span class="value">${remaining.toLocaleString()} ${this.#escapeHtml(mintInfo.symbol)}</span>
			</div>
			` : ""}
		`;

		// Aggregate balances by holder
		const balances = new Map<string, { label: string; total: number; isEscrow: boolean; lastMemo: string }>();
		for (const entry of this.#entries) {
			const existing = balances.get(entry.holder);
			if (existing) {
				existing.total += entry.amount;
				existing.lastMemo = entry.memo;
			} else {
				balances.set(entry.holder, {
					label: entry.holderLabel,
					total: entry.amount,
					isEscrow: this.#isEmail(entry.holder),
					lastMemo: entry.memo,
				});
			}
		}

		// Sort by balance descending
		const sorted = [...balances.entries()].sort((a, b) => b[1].total - a[1].total);

		if (sorted.length === 0) {
			this.#listEl.innerHTML = '<div class="empty-state">No tokens issued yet</div>';
		} else {
			this.#listEl.innerHTML = sorted
				.map(([holder, info]) => `
					<div class="holder-item">
						<div class="holder-info">
							<div class="holder-icon" style="background: ${info.isEscrow ? '#f59e0b' : this.#holderColor(holder)}">
								${info.isEscrow ? '✉' : info.label.charAt(0).toUpperCase()}
							</div>
							<div>
								<div class="holder-name">
									${this.#escapeHtml(info.label)}${info.isEscrow ? '<span class="escrow-badge">escrow</span>' : ''}
								</div>
								<div class="holder-memo">${this.#escapeHtml(info.lastMemo)}</div>
							</div>
						</div>
						<span class="holder-amount">${info.total.toLocaleString()} ${this.#escapeHtml(mintInfo.symbol)}</span>
					</div>
				`)
				.join("");
		}
	}

	static override fromData(data: Record<string, any>): FolkTokenLedger {
		const shape = FolkShape.fromData(data) as FolkTokenLedger;
		if (data.mintId !== undefined) shape.mintId = data.mintId;
		if (Array.isArray(data.entries)) shape.entries = data.entries;
		return shape;
	}

	override applyData(data: Record<string, any>): void {
		super.applyData(data);
		if (data.mintId !== undefined && data.mintId !== this.mintId) this.mintId = data.mintId;
		if (Array.isArray(data.entries) && JSON.stringify(data.entries) !== JSON.stringify(this.entries)) this.entries = data.entries;
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-token-ledger",
			mintId: this.#mintId,
			entries: this.#entries,
		};
	}
}
