/**
 * <folk-vote-dashboard> — conviction voting dashboard.
 *
 * Browse spaces, create/view proposals, cast votes (ranking + final).
 */

interface VoteSpace {
	slug: string;
	name: string;
	description: string;
	visibility: string;
	promotion_threshold: number;
	voting_period_days: number;
	credits_per_day: number;
	max_credits: number;
	starting_credits: number;
}

interface Proposal {
	id: string;
	title: string;
	description: string;
	status: string;
	score: number;
	vote_count: string;
	final_yes: number;
	final_no: number;
	final_abstain: number;
	created_at: string;
	voting_ends_at: string | null;
}

class FolkVoteDashboard extends HTMLElement {
	private shadow: ShadowRoot;
	private space = "";
	private view: "spaces" | "proposals" | "proposal" = "spaces";
	private spaces: VoteSpace[] = [];
	private selectedSpace: VoteSpace | null = null;
	private proposals: Proposal[] = [];
	private selectedProposal: Proposal | null = null;
	private loading = false;
	private error = "";

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

	connectedCallback() {
		this.space = this.getAttribute("space") || "demo";
		if (this.space === "demo") { this.loadDemoData(); return; }
		this.loadSpaces();
	}

	private loadDemoData() {
		this.spaces = [
			{
				slug: "community",
				name: "Community Governance",
				description: "Proposals for the rSpace ecosystem",
				visibility: "public_read",
				promotion_threshold: 100,
				voting_period_days: 7,
				credits_per_day: 10,
				max_credits: 500,
				starting_credits: 50,
			},
		];
		this.selectedSpace = this.spaces[0];
		this.view = "proposals";

		const now = Date.now();
		const day = 86400000;
		this.proposals = [
			{
				id: "p1",
				title: "Implement real-time collaboration in rNotes",
				description: "Use Automerge CRDTs (already in the stack) to enable simultaneous editing of notes, similar to how rSpace canvas works.",
				status: "RANKING",
				score: 72,
				vote_count: "9",
				final_yes: 0, final_no: 0, final_abstain: 0,
				created_at: new Date(now - 3 * day).toISOString(),
				voting_ends_at: null,
			},
			{
				id: "p2",
				title: "Add dark mode across all r* modules",
				description: "Implement a consistent dark theme with a toggle in shell.css. Use CSS custom properties for theming so each module inherits automatically.",
				status: "RANKING",
				score: 45,
				vote_count: "6",
				final_yes: 0, final_no: 0, final_abstain: 0,
				created_at: new Date(now - 5 * day).toISOString(),
				voting_ends_at: null,
			},
			{
				id: "p3",
				title: "Adopt cosmolocal print-on-demand for all merch",
				description: "Route all merchandise orders through the provider registry to find the closest printer. Reduces shipping emissions and supports local economies.",
				status: "VOTING",
				score: 105,
				vote_count: "14",
				final_yes: 5, final_no: 2, final_abstain: 0,
				created_at: new Date(now - 10 * day).toISOString(),
				voting_ends_at: new Date(now + 5 * day).toISOString(),
			},
			{
				id: "p4",
				title: "Use EncryptID passkeys for all authentication",
				description: "Standardize on WebAuthn passkeys via EncryptID across the entire r* ecosystem. One passkey, all apps.",
				status: "PASSED",
				score: 150,
				vote_count: "17",
				final_yes: 12, final_no: 3, final_abstain: 2,
				created_at: new Date(now - 21 * day).toISOString(),
				voting_ends_at: new Date(now - 7 * day).toISOString(),
			},
			{
				id: "p5",
				title: "Switch from PostgreSQL to SQLite for simpler deployment",
				description: "Evaluate replacing PostgreSQL with SQLite for modules that don't need concurrent writes.",
				status: "FAILED",
				score: 30,
				vote_count: "11",
				final_yes: 2, final_no: 8, final_abstain: 1,
				created_at: new Date(now - 18 * day).toISOString(),
				voting_ends_at: new Date(now - 4 * day).toISOString(),
			},
		];
		this.render();
	}

	private getApiBase(): string {
		const match = window.location.pathname.match(/^\/([^/]+)\/rvote/);
		if (match) return `/${match[1]}/rvote`;
		if (this.space) return `/${this.space}/rvote`;
		return "";
	}

	private async loadSpaces() {
		this.loading = true;
		this.render();
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/spaces`);
			const data = await res.json();
			this.spaces = data.spaces || [];
		} catch {
			this.error = "Failed to load spaces";
		}
		this.loading = false;
		this.render();
	}

	private async loadProposals(slug: string) {
		this.loading = true;
		this.render();
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/proposals?space_slug=${slug}`);
			const data = await res.json();
			this.proposals = data.proposals || [];
		} catch {
			this.error = "Failed to load proposals";
		}
		this.loading = false;
		this.render();
	}

	private async loadProposal(id: string) {
		this.loading = true;
		this.render();
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/proposals/${id}`);
			this.selectedProposal = await res.json();
		} catch {
			this.error = "Failed to load proposal";
		}
		this.loading = false;
		this.render();
	}

	private async castVote(proposalId: string, weight: number) {
		if (this.space === "demo") {
			const p = this.proposals.find(p => p.id === proposalId);
			if (p) {
				p.score += weight;
				p.vote_count = String(parseInt(p.vote_count) + 1);
				// Auto-promote if score reaches threshold (matches server-side behavior)
				const threshold = this.selectedSpace?.promotion_threshold || 100;
				if (p.score >= threshold && p.status === "RANKING") {
					p.status = "VOTING";
					const votingDays = this.selectedSpace?.voting_period_days || 7;
					p.voting_ends_at = new Date(Date.now() + votingDays * 86400000).toISOString();
				}
				this.selectedProposal = p;
			}
			this.render();
			return;
		}
		try {
			const base = this.getApiBase();
			await fetch(`${base}/api/proposals/${proposalId}/vote`, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ weight }),
			});
			await this.loadProposal(proposalId);
		} catch {
			this.error = "Failed to cast vote";
			this.render();
		}
	}

	private async castFinalVote(proposalId: string, vote: string) {
		if (this.space === "demo") {
			const p = this.proposals.find(p => p.id === proposalId);
			if (p) {
				if (vote === "YES") p.final_yes++;
				else if (vote === "NO") p.final_no++;
				else if (vote === "ABSTAIN") p.final_abstain++;
				this.selectedProposal = p;
			}
			this.render();
			return;
		}
		try {
			const base = this.getApiBase();
			await fetch(`${base}/api/proposals/${proposalId}/final-vote`, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ vote }),
			});
			await this.loadProposal(proposalId);
		} catch {
			this.error = "Failed to cast vote";
			this.render();
		}
	}

	private getStatusColor(status: string): string {
		switch (status) {
			case "RANKING": return "#3b82f6";
			case "VOTING": return "#f59e0b";
			case "PASSED": return "#22c55e";
			case "FAILED": return "#ef4444";
			case "ARCHIVED": return "#6b7280";
			default: return "#888";
		}
	}

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

			.rapp-nav { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; min-height: 36px; }
			.rapp-nav__back { padding: 4px 10px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); background: transparent; color: #94a3b8; cursor: pointer; font-size: 13px; }
			.rapp-nav__back:hover { color: #e2e8f0; border-color: rgba(255,255,255,0.2); }
			.rapp-nav__title { font-size: 15px; font-weight: 600; flex: 1; color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

			.card {
				background: #1e1e2e; border: 1px solid #333; border-radius: 10px;
				padding: 16px; margin-bottom: 12px; cursor: pointer; transition: border-color 0.2s;
			}
			.card:hover { border-color: #555; }
			.card-title { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
			.card-desc { font-size: 13px; color: #888; }
			.card-meta { display: flex; gap: 12px; margin-top: 8px; font-size: 12px; color: #666; }

			.badge {
				display: inline-block; padding: 2px 8px; border-radius: 4px;
				font-size: 11px; font-weight: 600; text-transform: uppercase;
			}

			.score-bar { height: 6px; border-radius: 3px; background: #333; margin-top: 6px; overflow: hidden; }
			.score-fill { height: 100%; border-radius: 3px; transition: width 0.3s; }

			.vote-controls { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
			.vote-btn {
				padding: 8px 16px; border-radius: 8px; border: 2px solid #333;
				background: #1e1e2e; color: #ccc; cursor: pointer; font-size: 14px;
				transition: all 0.2s;
			}
			.vote-btn:hover { border-color: #6366f1; }
			.vote-btn.yes { border-color: #22c55e; color: #22c55e; }
			.vote-btn.no { border-color: #ef4444; color: #ef4444; }
			.vote-btn.abstain { border-color: #f59e0b; color: #f59e0b; }

			.tally { display: flex; gap: 16px; margin-top: 12px; }
			.tally-item { text-align: center; }
			.tally-value { font-size: 24px; font-weight: 700; }
			.tally-label { font-size: 11px; color: #888; text-transform: uppercase; }

			.empty { text-align: center; color: #666; padding: 40px; }
			.loading { text-align: center; color: #888; padding: 40px; }
			.error { text-align: center; color: #ef5350; padding: 20px; }
		</style>

		${this.error ? `<div class="error">${this.esc(this.error)}</div>` : ""}
		${this.loading ? '<div class="loading">Loading...</div>' : ""}

		${!this.loading ? this.renderView() : ""}
		`;

		this.attachListeners();
	}

	private renderView(): string {
		if (this.view === "proposal" && this.selectedProposal) {
			return this.renderProposal();
		}
		if (this.view === "proposals" && this.selectedSpace) {
			return this.renderProposals();
		}
		return this.renderSpaces();
	}

	private renderSpaces(): string {
		return `
			<div class="rapp-nav">
				<span class="rapp-nav__title">Voting Spaces</span>
			</div>
			${this.spaces.length === 0 ? '<div class="empty">No voting spaces yet. Create one to get started.</div>' : ""}
			${this.spaces.map((s) => `
				<div class="card" data-space="${s.slug}">
					<div style="display:flex;justify-content:space-between;align-items:center">
						<div class="card-title">${this.esc(s.name)}</div>
						<span class="badge" style="background:rgba(129,140,248,0.15);color:#818cf8">${s.visibility === "public_read" ? "Public" : s.visibility}</span>
					</div>
					<div class="card-desc">${this.esc(s.description || "")}</div>
					<div class="card-meta">
						<span>Threshold: ${s.promotion_threshold}</span>
						<span>Voting: ${s.voting_period_days}d</span>
						<span>${s.credits_per_day} credits/day</span>
						<span>Max: ${s.max_credits}</span>
						<span>Start: ${s.starting_credits}</span>
					</div>
				</div>
			`).join("")}
		`;
	}

	private relativeTime(dateStr: string): string {
		const daysAgo = Math.floor((Date.now() - new Date(dateStr).getTime()) / 86400000);
		if (daysAgo === 0) return "today";
		if (daysAgo === 1) return "1 day ago";
		return `${daysAgo} days ago`;
	}

	private renderProposals(): string {
		const s = this.selectedSpace!;
		return `
			<div class="rapp-nav">
				<button class="rapp-nav__back" data-back="spaces">← Spaces</button>
				<span class="rapp-nav__title">${this.esc(s.name)} — Proposals</span>
			</div>
			${this.proposals.length === 0 ? '<div class="empty">No proposals yet.</div>' : ""}
			${this.proposals.map((p) => `
				<div class="card" data-proposal="${p.id}">
					<div style="display:flex;justify-content:space-between;align-items:center">
						<div class="card-title">${this.esc(p.title)}</div>
						<span class="badge" style="background:${this.getStatusColor(p.status)}20;color:${this.getStatusColor(p.status)}">${p.status}</span>
					</div>
					<div class="card-desc">${this.esc(p.description || "")}</div>
					${p.status === "RANKING" ? `
						<div class="score-bar">
							<div class="score-fill" style="width:${Math.min(100, (p.score / (s.promotion_threshold || 100)) * 100)}%;background:${this.getStatusColor(p.status)}"></div>
						</div>
						<div class="card-meta">
							<span>Score: ${Math.round(p.score)} / ${s.promotion_threshold}</span>
							<span>${p.vote_count} votes</span>
							<span>${this.relativeTime(p.created_at)}</span>
						</div>
					` : ""}
					${p.status === "VOTING" ? `
						<div class="card-meta">
							<span style="color:#22c55e">Yes: ${p.final_yes}</span>
							<span style="color:#ef4444">No: ${p.final_no}</span>
							<span style="color:#f59e0b">Abstain: ${p.final_abstain}</span>
							${p.voting_ends_at ? `<span>Ends: ${new Date(p.voting_ends_at).toLocaleDateString()}</span>` : ""}
						</div>
					` : ""}
					${p.status === "PASSED" || p.status === "FAILED" ? `
						<div class="card-meta">
							<span style="color:#22c55e">Yes: ${p.final_yes}</span>
							<span style="color:#ef4444">No: ${p.final_no}</span>
							<span style="color:#f59e0b">Abstain: ${p.final_abstain}</span>
							<span>${this.relativeTime(p.created_at)}</span>
						</div>
					` : ""}
				</div>
			`).join("")}
		`;
	}

	private renderProposal(): string {
		const p = this.selectedProposal!;
		const threshold = this.selectedSpace?.promotion_threshold || 100;
		const created = new Date(p.created_at);
		const daysAgo = Math.floor((Date.now() - created.getTime()) / 86400000);
		const ageText = daysAgo === 0 ? "today" : daysAgo === 1 ? "1 day ago" : `${daysAgo} days ago`;

		return `
			<div class="rapp-nav">
				<button class="rapp-nav__back" data-back="proposals">← Proposals</button>
				<span class="rapp-nav__title">${this.esc(p.title)}</span>
				<span class="badge" style="background:${this.getStatusColor(p.status)}20;color:${this.getStatusColor(p.status)};margin-left:8px">${p.status}</span>
			</div>
			<div class="card" style="cursor:default">
				<div class="card-desc" style="font-size:14px;color:#ccc;margin-bottom:12px">${this.esc(p.description || "No description")}</div>
				<div class="card-meta" style="margin-bottom:12px">
					<span>${p.vote_count} votes</span>
					<span>Created ${ageText}</span>
				</div>

				${p.status === "RANKING" ? `
					<div style="margin-bottom:8px;font-size:13px;color:#888">
						Conviction score: <strong style="color:#3b82f6">${Math.round(p.score)}</strong> / ${threshold}
					</div>
					<div class="score-bar">
						<div class="score-fill" style="width:${Math.min(100, (p.score / threshold) * 100)}%;background:#3b82f6"></div>
					</div>
					<div style="font-size:12px;color:#666;margin-top:4px">
						Needs ${threshold} to advance to voting (quadratic cost: weight&sup2; credits)
					</div>
					<div class="vote-controls">
						${[1, 2, 3, 5].map((w) => `
							<button class="vote-btn" data-vote-weight="${w}">
								+${w} (${w * w} credits)
							</button>
						`).join("")}
					</div>
				` : ""}

				${p.status === "VOTING" ? `
					<div style="margin-bottom:8px;font-size:13px;color:#888">
						Promoted with conviction score <strong style="color:#f59e0b">${Math.round(p.score)}</strong> — now in ${this.selectedSpace?.voting_period_days || 7}-day final vote
					</div>
					<div class="tally">
						<div class="tally-item"><div class="tally-value" style="color:#22c55e">${p.final_yes}</div><div class="tally-label">Yes</div></div>
						<div class="tally-item"><div class="tally-value" style="color:#ef4444">${p.final_no}</div><div class="tally-label">No</div></div>
						<div class="tally-item"><div class="tally-value" style="color:#f59e0b">${p.final_abstain}</div><div class="tally-label">Abstain</div></div>
					</div>
					<div class="vote-controls">
						<button class="vote-btn yes" data-final-vote="YES">Vote Yes</button>
						<button class="vote-btn no" data-final-vote="NO">Vote No</button>
						<button class="vote-btn abstain" data-final-vote="ABSTAIN">Abstain</button>
					</div>
					${p.voting_ends_at ? `<div style="font-size:12px;color:#666;margin-top:8px">Voting ends: ${new Date(p.voting_ends_at).toLocaleDateString()}</div>` : ""}
				` : ""}

				${p.status === "PASSED" || p.status === "FAILED" ? `
					<div style="margin-bottom:8px;font-size:13px;color:#888">
						Final result: <strong style="color:${this.getStatusColor(p.status)}">${p.status}</strong>
						(conviction score was ${Math.round(p.score)})
					</div>
					<div class="tally">
						<div class="tally-item"><div class="tally-value" style="color:#22c55e">${p.final_yes}</div><div class="tally-label">Yes</div></div>
						<div class="tally-item"><div class="tally-value" style="color:#ef4444">${p.final_no}</div><div class="tally-label">No</div></div>
						<div class="tally-item"><div class="tally-value" style="color:#f59e0b">${p.final_abstain}</div><div class="tally-label">Abstain</div></div>
					</div>
				` : ""}
			</div>
		`;
	}

	private attachListeners() {
		// Space cards
		this.shadow.querySelectorAll("[data-space]").forEach((el) => {
			el.addEventListener("click", () => {
				const slug = (el as HTMLElement).dataset.space!;
				this.selectedSpace = this.spaces.find((s) => s.slug === slug) || null;
				this.view = "proposals";
				if (this.space === "demo") {
					this.render();
				} else {
					this.loadProposals(slug);
				}
			});
		});

		// Proposal cards
		this.shadow.querySelectorAll("[data-proposal]").forEach((el) => {
			el.addEventListener("click", () => {
				const id = (el as HTMLElement).dataset.proposal!;
				this.view = "proposal";
				if (this.space === "demo") {
					this.selectedProposal = this.proposals.find((p) => p.id === id) || null;
					this.render();
				} else {
					this.loadProposal(id);
				}
			});
		});

		// Back buttons
		this.shadow.querySelectorAll("[data-back]").forEach((el) => {
			el.addEventListener("click", (e) => {
				e.stopPropagation();
				const target = (el as HTMLElement).dataset.back;
				if (target === "spaces") { this.view = "spaces"; this.render(); }
				else if (target === "proposals") { this.view = "proposals"; this.render(); }
			});
		});

		// Conviction vote buttons
		this.shadow.querySelectorAll("[data-vote-weight]").forEach((el) => {
			el.addEventListener("click", (e) => {
				e.stopPropagation();
				const weight = parseInt((el as HTMLElement).dataset.voteWeight!);
				if (this.selectedProposal) this.castVote(this.selectedProposal.id, weight);
			});
		});

		// Final vote buttons
		this.shadow.querySelectorAll("[data-final-vote]").forEach((el) => {
			el.addEventListener("click", (e) => {
				e.stopPropagation();
				const vote = (el as HTMLElement).dataset.finalVote!;
				if (this.selectedProposal) this.castFinalVote(this.selectedProposal.id, vote);
			});
		});
	}

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

customElements.define("folk-vote-dashboard", FolkVoteDashboard);
