/**
 * <folk-wallet-viewer> — multichain Safe wallet visualization.
 *
 * Enter a Safe address to see balances across chains, transfer history,
 * and flow visualizations.
 */

interface ChainInfo {
	chainId: string;
	name: string;
	prefix: string;
	color: string;
}

interface BalanceItem {
	tokenAddress: string | null;
	token: { name: string; symbol: string; decimals: number } | null;
	balance: string;
	fiatBalance: string;
	fiatConversion: string;
}

const CHAIN_COLORS: Record<string, string> = {
	"1": "#627eea",
	"10": "#ff0420",
	"100": "#04795b",
	"137": "#8247e5",
	"8453": "#0052ff",
	"42161": "#28a0f0",
	"42220": "#35d07f",
	"43114": "#e84142",
	"56": "#f3ba2f",
	"324": "#8c8dfc",
};

class FolkWalletViewer extends HTMLElement {
	private shadow: ShadowRoot;
	private address = "";
	private detectedChains: ChainInfo[] = [];
	private selectedChain: string | null = null;
	private balances: BalanceItem[] = [];
	private loading = false;
	private error = "";
	private isDemo = false;

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

	connectedCallback() {
		const space = this.getAttribute("space") || "";
		if (space === "demo") {
			this.loadDemoData();
			return;
		}
		// Check URL params for initial address
		const params = new URLSearchParams(window.location.search);
		this.address = params.get("address") || "";
		this.render();
		if (this.address) this.detectChains();
	}

	private loadDemoData() {
		this.isDemo = true;
		this.address = "0x29567BdBcC92aCF37AC6B56B69180857bB69f7D1";
		this.detectedChains = [
			{ chainId: "1", name: "Ethereum", prefix: "eth", color: "#627eea" },
			{ chainId: "10", name: "Optimism", prefix: "oeth", color: "#ff0420" },
			{ chainId: "100", name: "Gnosis", prefix: "gno", color: "#04795b" },
			{ chainId: "137", name: "Polygon", prefix: "pol", color: "#8247e5" },
			{ chainId: "8453", name: "Base", prefix: "base", color: "#0052ff" },
			{ chainId: "42161", name: "Arbitrum", prefix: "arb1", color: "#28a0f0" },
			{ chainId: "43114", name: "Avalanche", prefix: "avax", color: "#e84142" },
		];
		this.selectedChain = "100";
		this.balances = [
			{ tokenAddress: null, token: { name: "xDAI", symbol: "xDAI", decimals: 18 }, balance: "45230000000000000000000", fiatBalance: "45230", fiatConversion: "1" },
			{ tokenAddress: "0x5dF8339c5E282ee48c0c7cE252A7842F74e378b2", token: { name: "Token Engineering Commons", symbol: "TEC", decimals: 18 }, balance: "1250000000000000000000000", fiatBalance: "12500", fiatConversion: "0.01" },
			{ tokenAddress: "0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1", token: { name: "Wrapped Ether", symbol: "WETH", decimals: 18 }, balance: "8500000000000000000", fiatBalance: "28050", fiatConversion: "3300" },
			{ tokenAddress: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83", token: { name: "USD Coin", symbol: "USDC", decimals: 6 }, balance: "15750000000", fiatBalance: "15750", fiatConversion: "1" },
			{ tokenAddress: "0x4f4F9b8D5B4d0Dc10506e5551B0513B61fD59e75", token: { name: "Giveth", symbol: "GIV", decimals: 18 }, balance: "500000000000000000000000", fiatBalance: "2500", fiatConversion: "0.005" },
		];
		this.render();
	}

	private getApiBase(): string {
		const path = window.location.pathname;
		const match = path.match(/^(\/[^/]+)?\/rwallet/);
		return match ? match[0] : "";
	}

	private async detectChains() {
		if (this.isDemo) return;
		if (!this.address || !/^0x[a-fA-F0-9]{40}$/.test(this.address)) {
			this.error = "Please enter a valid Ethereum address (0x...)";
			this.render();
			return;
		}

		this.loading = true;
		this.error = "";
		this.detectedChains = [];
		this.balances = [];
		this.render();

		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/safe/detect/${this.address}`);
			const data = await res.json();

			this.detectedChains = (data.chains || []).map((c: any) => ({
				...c,
				color: CHAIN_COLORS[c.chainId] || "#888",
			}));

			if (this.detectedChains.length === 0) {
				this.error = "No Safe wallets found for this address on any supported chain.";
			} else {
				// Auto-select first chain
				this.selectedChain = this.detectedChains[0].chainId;
				await this.loadBalances();
			}
		} catch (e) {
			this.error = "Failed to detect chains. Check the address and try again.";
		}

		this.loading = false;
		this.render();
	}

	private async loadBalances() {
		if (this.isDemo) return;
		if (!this.selectedChain) return;
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/safe/${this.selectedChain}/${this.address}/balances`);
			if (res.ok) {
				this.balances = await res.json();
			}
		} catch {
			this.balances = [];
		}
	}

	private formatBalance(balance: string, decimals: number): string {
		const val = Number(balance) / Math.pow(10, decimals);
		if (val >= 1000000) return `${(val / 1000000).toFixed(2)}M`;
		if (val >= 1000) return `${(val / 1000).toFixed(2)}K`;
		if (val >= 1) return val.toFixed(2);
		if (val >= 0.0001) return val.toFixed(4);
		return val.toExponential(2);
	}

	private formatUSD(val: string): string {
		const n = parseFloat(val);
		if (isNaN(n) || n === 0) return "$0";
		if (n >= 1000000) return `$${(n / 1000000).toFixed(2)}M`;
		if (n >= 1000) return `$${(n / 1000).toFixed(1)}K`;
		return `$${n.toFixed(2)}`;
	}

	private shortenAddress(addr: string): string {
		return `${addr.slice(0, 6)}...${addr.slice(-4)}`;
	}

	private handleSubmit(e: Event) {
		e.preventDefault();
		const input = this.shadow.querySelector("#address-input") as HTMLInputElement;
		if (input) {
			this.address = input.value.trim();
			const url = new URL(window.location.href);
			url.searchParams.set("address", this.address);
			window.history.replaceState({}, "", url.toString());
			this.detectChains();
		}
	}

	private async handleChainSelect(chainId: string) {
		this.selectedChain = chainId;
		if (this.isDemo) {
			this.render();
			return;
		}
		this.loading = true;
		this.render();
		await this.loadBalances();
		this.loading = false;
		this.render();
	}

	private render() {
		const totalUSD = this.balances.reduce((sum, b) => sum + parseFloat(b.fiatBalance || "0"), 0);

		this.shadow.innerHTML = `
		<style>
			:host { display: block; font-family: system-ui, -apple-system, sans-serif; color: #e0e0e0; }
			* { box-sizing: border-box; }

			.address-bar { display: flex; gap: 8px; margin-bottom: 24px; }
			.address-bar input {
				flex: 1; padding: 10px 14px; border-radius: 8px;
				border: 1px solid #444; background: #2a2a3e; color: #e0e0e0;
				font-family: monospace; font-size: 13px;
			}
			.address-bar input:focus { border-color: #00d4ff; outline: none; }
			.address-bar button {
				padding: 10px 20px; border-radius: 8px; border: none;
				background: #00d4ff; color: #000; font-weight: 600; cursor: pointer;
			}
			.address-bar button:hover { background: #00b8d9; }

			.chains { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
			.chain-btn {
				padding: 6px 14px; border-radius: 8px; border: 2px solid #333;
				background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 13px;
				display: flex; align-items: center; gap: 6px; transition: all 0.2s;
			}
			.chain-btn:hover { border-color: #555; }
			.chain-btn.active { border-color: var(--chain-color); background: rgba(255,255,255,0.05); }
			.chain-dot { width: 8px; height: 8px; border-radius: 50%; }

			.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 24px; }
			.stat-card {
				background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
				padding: 14px; text-align: center;
			}
			.stat-label { font-size: 11px; color: #888; text-transform: uppercase; margin-bottom: 6px; }
			.stat-value { font-size: 20px; font-weight: 700; color: #00d4ff; }

			.balance-table { width: 100%; border-collapse: collapse; }
			.balance-table th {
				text-align: left; padding: 10px 8px; border-bottom: 2px solid #333;
				color: #888; font-size: 11px; text-transform: uppercase;
			}
			.balance-table td { padding: 10px 8px; border-bottom: 1px solid #2a2a3e; }
			.balance-table tr:hover td { background: rgba(255,255,255,0.02); }
			.token-symbol { font-weight: 600; color: #e0e0e0; }
			.token-name { font-size: 12px; color: #888; }
			.amount-cell { text-align: right; font-family: monospace; }
			.fiat { color: #4ade80; }

			.empty { text-align: center; color: #666; padding: 40px; }
			.loading { text-align: center; color: #888; padding: 40px; }
			.error { text-align: center; color: #ef5350; padding: 20px; }
			.demo-link { color: #00d4ff; cursor: pointer; text-decoration: underline; }

			@media (max-width: 768px) {
				.balance-table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
				.address-bar { flex-wrap: wrap; }
				.address-bar input { min-width: 0; }
				.chains { flex-wrap: wrap; }
			}
		</style>

		<form class="address-bar" id="address-form">
			<input id="address-input" type="text" placeholder="Enter Safe address (0x...)"
				value="${this.address}" spellcheck="false">
			<button type="submit">Load</button>
		</form>

		${!this.address && !this.loading ? `
			<div class="empty">
				<p style="font-size:16px;margin-bottom:8px">Enter a Safe wallet address to visualize</p>
				<p>Try: <span class="demo-link" data-address="0x29567BdBcC92aCF37AC6B56B69180857bB69f7D1">TEC Commons Fund</span></p>
			</div>
		` : ""}

		${this.error ? `<div class="error">${this.esc(this.error)}</div>` : ""}
		${this.loading ? '<div class="loading">Detecting Safe wallets across chains...</div>' : ""}

		${!this.loading && this.detectedChains.length > 0 ? `
			<div class="chains">
				${this.detectedChains.map((ch) => `
					<div class="chain-btn ${this.selectedChain === ch.chainId ? "active" : ""}"
						data-chain="${ch.chainId}" style="--chain-color: ${ch.color}">
						<div class="chain-dot" style="background: ${ch.color}"></div>
						${ch.name}
					</div>
				`).join("")}
			</div>

			<div class="stats">
				<div class="stat-card">
					<div class="stat-label">Total Value</div>
					<div class="stat-value">${this.formatUSD(String(totalUSD))}</div>
				</div>
				<div class="stat-card">
					<div class="stat-label">Tokens</div>
					<div class="stat-value">${this.balances.filter((b) => parseFloat(b.fiatBalance || "0") > 0).length}</div>
				</div>
				<div class="stat-card">
					<div class="stat-label">Chains</div>
					<div class="stat-value">${this.detectedChains.length}</div>
				</div>
				<div class="stat-card">
					<div class="stat-label">Address</div>
					<div class="stat-value" style="font-size:13px;font-family:monospace">${this.shortenAddress(this.address)}</div>
				</div>
			</div>

			${this.balances.length > 0 ? `
				<table class="balance-table">
					<thead>
						<tr><th>Token</th><th class="amount-cell">Balance</th><th class="amount-cell">USD Value</th></tr>
					</thead>
					<tbody>
						${this.balances
							.filter((b) => parseFloat(b.fiatBalance || "0") > 0.01)
							.sort((a, b) => parseFloat(b.fiatBalance || "0") - parseFloat(a.fiatBalance || "0"))
							.map((b) => `
								<tr>
									<td>
										<span class="token-symbol">${b.token?.symbol || "ETH"}</span>
										<span class="token-name">${b.token?.name || "Ether"}</span>
									</td>
									<td class="amount-cell">${this.formatBalance(b.balance, b.token?.decimals || 18)}</td>
									<td class="amount-cell fiat">${this.formatUSD(b.fiatBalance)}</td>
								</tr>
							`).join("")}
					</tbody>
				</table>
			` : '<div class="empty">No balances found on this chain.</div>'}
		` : ""}
		`;

		// Event listeners
		const form = this.shadow.querySelector("#address-form");
		form?.addEventListener("submit", (e) => this.handleSubmit(e));

		this.shadow.querySelectorAll(".chain-btn").forEach((btn) => {
			btn.addEventListener("click", () => {
				const chainId = (btn as HTMLElement).dataset.chain!;
				this.handleChainSelect(chainId);
			});
		});

		this.shadow.querySelectorAll(".demo-link").forEach((link) => {
			link.addEventListener("click", () => {
				const addr = (link as HTMLElement).dataset.address!;
				const input = this.shadow.querySelector("#address-input") as HTMLInputElement;
				if (input) input.value = addr;
				this.address = addr;
				this.detectChains();
			});
		});
	}

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

customElements.define("folk-wallet-viewer", FolkWalletViewer);
