/**
 * <folk-transaction-builder> — Safe multi-sig transaction builder canvas shape.
 * Three modes: Compose, Pending, History.
 * Uses existing rwallet API endpoints for propose/confirm/execute.
 */

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

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: 380px;
		min-height: 480px;
	}

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

	/* Safe selector */
	.safe-selector {
		display: flex;
		gap: 6px;
		padding: 8px 12px;
		border-bottom: 1px solid var(--rs-border, #e2e8f0);
		font-size: 12px;
	}
	.safe-selector input, .safe-selector select {
		flex: 1;
		padding: 5px 8px;
		border: 1px solid var(--rs-input-border, #e2e8f0);
		border-radius: 6px;
		font-size: 11px;
		background: var(--rs-input-bg, #fff);
		color: var(--rs-input-text, inherit);
		outline: none;
	}
	.safe-selector select { flex: 0 0 100px; }
	.safe-selector input:focus { border-color: #7c3aed; }

	/* Tabs */
	.tabs {
		display: flex;
		border-bottom: 1px solid var(--rs-border, #e2e8f0);
	}
	.tab {
		flex: 1;
		padding: 8px;
		text-align: center;
		font-size: 12px;
		font-weight: 600;
		color: #64748b;
		border: none;
		background: none;
		cursor: pointer;
		border-bottom: 2px solid transparent;
		transition: all 0.2s;
	}
	.tab:hover { color: #7c3aed; }
	.tab.active { color: #7c3aed; border-bottom-color: #7c3aed; }

	/* Tab panels */
	.tab-panel {
		display: none;
		flex: 1;
		overflow-y: auto;
		padding: 12px;
	}
	.tab-panel.active { display: flex; flex-direction: column; gap: 10px; }

	/* Form elements */
	label {
		display: flex;
		flex-direction: column;
		gap: 3px;
		font-size: 11px;
		font-weight: 600;
		color: #64748b;
	}
	input, textarea {
		padding: 7px 10px;
		border: 1px solid var(--rs-input-border, #e2e8f0);
		border-radius: 6px;
		font-size: 12px;
		background: var(--rs-input-bg, #fff);
		color: var(--rs-input-text, inherit);
		outline: none;
		font-family: inherit;
	}
	input:focus, textarea:focus { border-color: #7c3aed; }
	textarea { resize: vertical; min-height: 50px; }

	.btn {
		padding: 8px 16px;
		border: none;
		border-radius: 6px;
		font-size: 12px;
		font-weight: 600;
		cursor: pointer;
		transition: opacity 0.2s;
	}
	.btn:hover { opacity: 0.9; }
	.btn:disabled { opacity: 0.5; cursor: not-allowed; }
	.btn-primary {
		background: linear-gradient(135deg, #7c3aed, #6366f1);
		color: white;
	}
	.btn-success {
		background: #10b981;
		color: white;
	}
	.btn-warning {
		background: #f59e0b;
		color: white;
	}

	/* Transaction cards */
	.tx-card {
		border: 1px solid var(--rs-border, #e2e8f0);
		border-radius: 8px;
		padding: 10px 12px;
		font-size: 12px;
	}
	.tx-card-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 6px;
	}
	.tx-card-header .nonce {
		font-weight: 700;
		color: #7c3aed;
	}
	.tx-card-header .status {
		font-size: 10px;
		padding: 2px 8px;
		border-radius: 10px;
		font-weight: 600;
	}
	.status-pending { background: #fef3c7; color: #92400e; }
	.status-executed { background: #d1fae5; color: #065f46; }
	.status-failed { background: #fee2e2; color: #991b1b; }

	.tx-card .detail {
		display: flex;
		justify-content: space-between;
		color: #64748b;
		font-size: 11px;
		margin-top: 4px;
	}
	.tx-card .addr {
		font-family: 'SF Mono', Monaco, monospace;
		font-size: 10px;
		color: #475569;
	}
	.tx-card .actions {
		display: flex;
		gap: 6px;
		margin-top: 8px;
	}

	.empty-state {
		text-align: center;
		padding: 40px 20px;
		color: #94a3b8;
		font-size: 13px;
	}
	.empty-state .icon { font-size: 32px; margin-bottom: 8px; }

	.info-bar {
		font-size: 11px;
		padding: 6px 12px;
		background: #f0f9ff;
		color: #0369a1;
		border-radius: 6px;
		text-align: center;
	}

	.error-bar {
		font-size: 11px;
		padding: 6px 12px;
		background: #fef2f2;
		color: #991b1b;
		border-radius: 6px;
		text-align: center;
	}

	.loading {
		text-align: center;
		padding: 20px;
		color: #94a3b8;
		font-size: 12px;
	}
`;

const CHAINS: Record<string, { name: string; explorer: string }> = {
	"1":     { name: "Ethereum",  explorer: "https://etherscan.io" },
	"10":    { name: "Optimism",  explorer: "https://optimistic.etherscan.io" },
	"100":   { name: "Gnosis",    explorer: "https://gnosisscan.io" },
	"137":   { name: "Polygon",   explorer: "https://polygonscan.com" },
	"42161": { name: "Arbitrum",  explorer: "https://arbiscan.io" },
	"8453":  { name: "Base",      explorer: "https://basescan.org" },
};

export class FolkTransactionBuilder extends FolkShape {
	static override tagName = "folk-transaction-builder";

	#safeAddress = "";
	#chainId = "100"; // Default to Gnosis
	#activeTab: "compose" | "pending" | "history" = "compose";
	#statusMessage = "";
	#statusType: "info" | "error" = "info";
	#loading = false;
	#pendingTxs: any[] = [];
	#historyTxs: any[] = [];
	#safeInfo: any = null;

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

	override connectedCallback() {
		super.connectedCallback();
		this.#render();
	}

	#getToken(): string | null {
		try {
			const sess = JSON.parse(localStorage.getItem("encryptid_session") || "{}");
			return sess?.accessToken || null;
		} catch { return null; }
	}

	#getSpaceSlug(): string {
		return (window as any).__spaceSlug || location.pathname.split("/")[1] || "demo";
	}

	#apiBase(): string {
		return `${getModuleApiBase("rwallet")}/api/safe/${this.#chainId}/${this.#safeAddress}`;
	}

	async #apiFetch(path: string, opts?: RequestInit): Promise<any> {
		const token = this.#getToken();
		const headers: Record<string, string> = {
			"Content-Type": "application/json",
			...(token ? { Authorization: `Bearer ${token}` } : {}),
		};
		const res = await fetch(`${this.#apiBase()}${path}`, { ...opts, headers });
		if (!res.ok) {
			const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
			throw new Error(err.error || `HTTP ${res.status}`);
		}
		return res.json();
	}

	async #loadSafeInfo() {
		if (!this.#safeAddress) return;
		try {
			this.#safeInfo = await this.#apiFetch("/info");
			this.#render();
		} catch (e: any) {
			this.#showStatus(`Safe info: ${e.message}`, "error");
		}
	}

	async #loadPendingTxs() {
		if (!this.#safeAddress) return;
		this.#loading = true;
		this.#render();
		try {
			const data = await this.#apiFetch("/transfers");
			// Filter to pending (not executed) — transfers endpoint returns all
			this.#pendingTxs = (data.results || []).filter((tx: any) => !tx.executionDate && tx.isQueued !== false);
			this.#historyTxs = (data.results || []).filter((tx: any) => !!tx.executionDate);
		} catch (e: any) {
			this.#showStatus(`Load error: ${e.message}`, "error");
		}
		this.#loading = false;
		this.#render();
	}

	#showStatus(msg: string, type: "info" | "error" = "info") {
		this.#statusMessage = msg;
		this.#statusType = type;
		this.#render();
		if (type === "info") setTimeout(() => { this.#statusMessage = ""; this.#render(); }, 5000);
	}

	async #proposeTx() {
		const root = this.shadowRoot!;
		const to = (root.querySelector("#tx-to") as HTMLInputElement)?.value?.trim();
		const value = (root.querySelector("#tx-value") as HTMLInputElement)?.value?.trim() || "0";
		const data = (root.querySelector("#tx-data") as HTMLTextAreaElement)?.value?.trim() || "0x";
		const desc = (root.querySelector("#tx-desc") as HTMLInputElement)?.value?.trim();

		if (!to) { this.#showStatus("Recipient address required", "error"); return; }

		this.#loading = true;
		this.#render();
		try {
			await this.#apiFetch("/propose", {
				method: "POST",
				body: JSON.stringify({ to, value, data, description: desc }),
			});
			this.#showStatus("Transaction proposed");
			// Clear form
			const toEl = root.querySelector("#tx-to") as HTMLInputElement;
			if (toEl) toEl.value = "";
			const valEl = root.querySelector("#tx-value") as HTMLInputElement;
			if (valEl) valEl.value = "";
			const dataEl = root.querySelector("#tx-data") as HTMLTextAreaElement;
			if (dataEl) dataEl.value = "";
			const descEl = root.querySelector("#tx-desc") as HTMLInputElement;
			if (descEl) descEl.value = "";
			// Refresh pending
			await this.#loadPendingTxs();
		} catch (e: any) {
			this.#showStatus(`Propose failed: ${e.message}`, "error");
		}
		this.#loading = false;
		this.#render();
	}

	async #confirmTx(safeTxHash: string) {
		this.#loading = true;
		this.#render();
		try {
			await this.#apiFetch("/confirm", {
				method: "POST",
				body: JSON.stringify({ safeTxHash }),
			});
			this.#showStatus("Transaction confirmed");
			await this.#loadPendingTxs();
		} catch (e: any) {
			this.#showStatus(`Confirm failed: ${e.message}`, "error");
		}
		this.#loading = false;
		this.#render();
	}

	async #executeTx(safeTxHash: string) {
		this.#loading = true;
		this.#render();
		try {
			await this.#apiFetch("/execute", {
				method: "POST",
				body: JSON.stringify({ safeTxHash }),
			});
			this.#showStatus("Transaction executed");
			await this.#loadPendingTxs();
		} catch (e: any) {
			this.#showStatus(`Execute failed: ${e.message}`, "error");
		}
		this.#loading = false;
		this.#render();
	}

	#shortenAddr(addr: string): string {
		if (!addr || addr.length < 12) return addr || "";
		return addr.slice(0, 6) + "..." + addr.slice(-4);
	}

	#setTab(tab: "compose" | "pending" | "history") {
		this.#activeTab = tab;
		if (tab === "pending" || tab === "history") this.#loadPendingTxs();
		this.#render();
	}

	#render() {
		const root = this.shadowRoot;
		if (!root) return;

		const chain = CHAINS[this.#chainId] || { name: `Chain ${this.#chainId}`, explorer: "" };
		const threshold = this.#safeInfo?.threshold || "?";

		root.innerHTML = `
			<div class="header">
				<div class="header-title">🔐 Transaction Builder</div>
				<div class="header-actions">
					<button class="refresh-btn" title="Refresh">↻</button>
				</div>
			</div>
			<div class="content">
				<div class="safe-selector">
					<input id="safe-addr" type="text" placeholder="Safe address (0x...)" value="${this.#safeAddress}" />
					<select id="chain-select">
						${Object.entries(CHAINS).map(([id, c]) =>
							`<option value="${id}" ${id === this.#chainId ? "selected" : ""}>${c.name}</option>`
						).join("")}
					</select>
				</div>

				<div class="tabs">
					<button class="tab ${this.#activeTab === "compose" ? "active" : ""}" data-tab="compose">Compose</button>
					<button class="tab ${this.#activeTab === "pending" ? "active" : ""}" data-tab="pending">Pending</button>
					<button class="tab ${this.#activeTab === "history" ? "active" : ""}" data-tab="history">History</button>
				</div>

				${this.#statusMessage ? `<div class="${this.#statusType === "error" ? "error-bar" : "info-bar"}">${this.#escapeHtml(this.#statusMessage)}</div>` : ""}

				<!-- Compose -->
				<div class="tab-panel ${this.#activeTab === "compose" ? "active" : ""}">
					${this.#safeAddress ? `
						<div class="info-bar">Safe on ${chain.name} | Threshold: ${threshold}</div>
						<label>Recipient Address
							<input id="tx-to" type="text" placeholder="0x..." />
						</label>
						<label>Value (wei)
							<input id="tx-value" type="text" placeholder="0" />
						</label>
						<label>Description
							<input id="tx-desc" type="text" placeholder="What is this transaction for?" />
						</label>
						<label>Calldata (optional)
							<textarea id="tx-data" placeholder="0x"></textarea>
						</label>
						<button class="btn btn-primary propose-btn" ${this.#loading ? "disabled" : ""}>
							${this.#loading ? "Proposing..." : "Propose Transaction"}
						</button>
					` : `
						<div class="empty-state">
							<div class="icon">🔐</div>
							Enter a Safe address above to start
						</div>
					`}
				</div>

				<!-- Pending -->
				<div class="tab-panel ${this.#activeTab === "pending" ? "active" : ""}">
					${this.#loading ? '<div class="loading">Loading...</div>' :
					  this.#pendingTxs.length === 0 ? `
						<div class="empty-state">
							<div class="icon">✅</div>
							No pending transactions
						</div>
					` : this.#pendingTxs.map(tx => `
						<div class="tx-card">
							<div class="tx-card-header">
								<span class="nonce">#${tx.nonce ?? "?"}</span>
								<span class="status status-pending">${tx.confirmations?.length || 0}/${threshold} confirmed</span>
							</div>
							<div class="addr">To: ${this.#shortenAddr(tx.to)}</div>
							<div class="detail">
								<span>Value: ${tx.value || "0"} wei</span>
							</div>
							<div class="actions">
								<button class="btn btn-success confirm-btn" data-hash="${tx.safeTxHash || ""}">Confirm</button>
								<button class="btn btn-warning execute-btn" data-hash="${tx.safeTxHash || ""}">Execute</button>
							</div>
						</div>
					`).join("")}
				</div>

				<!-- History -->
				<div class="tab-panel ${this.#activeTab === "history" ? "active" : ""}">
					${this.#loading ? '<div class="loading">Loading...</div>' :
					  this.#historyTxs.length === 0 ? `
						<div class="empty-state">
							<div class="icon">📜</div>
							No transaction history
						</div>
					` : this.#historyTxs.slice(0, 50).map(tx => {
						const executed = !!tx.executionDate;
						return `
						<div class="tx-card">
							<div class="tx-card-header">
								<span class="nonce">#${tx.nonce ?? "?"}</span>
								<span class="status ${executed ? "status-executed" : "status-failed"}">${executed ? "Executed" : "Failed"}</span>
							</div>
							<div class="addr">To: ${this.#shortenAddr(tx.to)}</div>
							<div class="detail">
								<span>Value: ${tx.value || "0"} wei</span>
								<span>${tx.executionDate ? new Date(tx.executionDate).toLocaleDateString() : ""}</span>
							</div>
							${tx.transactionHash && chain.explorer ? `
								<div class="detail">
									<a href="${chain.explorer}/tx/${tx.transactionHash}" target="_blank" style="color: #7c3aed; text-decoration: none; font-size: 10px;">View on explorer ↗</a>
								</div>
							` : ""}
						</div>`;
					}).join("")}
				</div>
			</div>
		`;

		// Re-attach event listeners
		root.querySelector("#safe-addr")?.addEventListener("change", (e) => {
			this.#safeAddress = (e.target as HTMLInputElement).value.trim();
			this.#loadSafeInfo();
			this.dispatchEvent(new CustomEvent("folk-transform", { bubbles: true }));
		});
		root.querySelector("#chain-select")?.addEventListener("change", (e) => {
			this.#chainId = (e.target as HTMLSelectElement).value;
			if (this.#safeAddress) this.#loadSafeInfo();
			this.dispatchEvent(new CustomEvent("folk-transform", { bubbles: true }));
		});
		root.querySelectorAll(".tab").forEach(tab => {
			tab.addEventListener("click", () => this.#setTab(tab.getAttribute("data-tab") as any));
		});
		root.querySelector(".propose-btn")?.addEventListener("click", () => this.#proposeTx());
		root.querySelectorAll(".confirm-btn").forEach(btn => {
			btn.addEventListener("click", () => this.#confirmTx(btn.getAttribute("data-hash") || ""));
		});
		root.querySelectorAll(".execute-btn").forEach(btn => {
			btn.addEventListener("click", () => this.#executeTx(btn.getAttribute("data-hash") || ""));
		});
		root.querySelector(".refresh-btn")?.addEventListener("click", () => {
			if (this.#safeAddress) {
				this.#loadSafeInfo();
				this.#loadPendingTxs();
			}
		});
	}

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

	static override fromData(data: Record<string, any>): FolkTransactionBuilder {
		const shape = FolkShape.fromData(data) as FolkTransactionBuilder;
		return shape;
	}

	override toJSON() {
		return {
			...super.toJSON(),
			type: "folk-transaction-builder",
			safeAddress: this.#safeAddress,
			chainId: this.#chainId,
		};
	}

	override applyData(data: Record<string, any>): void {
		super.applyData(data);
		if (data.safeAddress !== undefined) this.#safeAddress = data.safeAddress;
		if (data.chainId !== undefined) this.#chainId = data.chainId;
		this.#render();
	}
}

if (!customElements.get("folk-transaction-builder")) {
	customElements.define("folk-transaction-builder", FolkTransactionBuilder);
}
