/**
 * <folk-delegation-manager> — per-vertical delegation management UI.
 *
 * Shows bars for each authority vertical (gov-ops, fin-ops, dev-ops)
 * with percentage allocated and delegate avatars. Supports create, edit, revoke.
 * Weight sum validated client-side before submission.
 */

interface Delegation {
	id: string;
	delegatorDid: string;
	delegateDid: string;
	authority: string;
	weight: number;
	maxDepth: number;
	retainAuthority: boolean;
	spaceSlug: string;
	state: string;
	customScope: string | null;
	expiresAt: number | null;
	createdAt: number;
	updatedAt: number;
}

interface SpaceUser {
	did: string;
	username: string;
	displayName: string | null;
	avatarUrl: string | null;
	role: string;
}

const AUTHORITIES = ["gov-ops", "fin-ops", "dev-ops"] as const;
const DM_AUTHORITY_DISPLAY: Record<string, { label: string; color: string }> = {
	"gov-ops": { label: "Gov", color: "#a78bfa" },
	"fin-ops": { label: "Econ", color: "#10b981" },
	"dev-ops": { label: "Tech", color: "#3b82f6" },
};
const AUTHORITY_ICONS: Record<string, string> = {
	"gov-ops": "\u{1F3DB}\uFE0F",
	"fin-ops": "\u{1F4B0}",
	"dev-ops": "\u{1F528}",
};

class FolkDelegationManager extends HTMLElement {
	private shadow: ShadowRoot;
	private space = "";
	private outbound: Delegation[] = [];
	private inbound: Delegation[] = [];
	private users: SpaceUser[] = [];
	private loading = true;
	private error = "";
	private showModal = false;
	private modalAuthority = "voting";
	private modalDelegate = "";
	private modalWeight = 50;
	private modalMaxDepth = 3;
	private modalRetainAuthority = true;
	private editingId: string | null = null;

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

	connectedCallback() {
		this.space = this.getAttribute("space") || "demo";
		this.render();
		this.loadData();
	}

	private getAuthBase(): string {
		return this.getAttribute("auth-url") || "";
	}

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

	private getAuthHeaders(): Record<string, string> {
		const token = localStorage.getItem("encryptid_session");
		if (!token) return {};
		return { Authorization: `Bearer ${token}` };
	}

	private async loadData() {
		const authBase = this.getAuthBase();
		const apiBase = this.getApiBase();
		const headers = this.getAuthHeaders();

		try {
			const [outRes, inRes, usersRes] = await Promise.all([
				fetch(`${authBase}/api/delegations/from?space=${encodeURIComponent(this.space)}`, { headers }),
				fetch(`${authBase}/api/delegations/to?space=${encodeURIComponent(this.space)}`, { headers }),
				fetch(`${apiBase}/api/users?space=${encodeURIComponent(this.space)}`),
			]);

			if (outRes.ok) {
				const d = await outRes.json();
				this.outbound = d.delegations || [];
			}
			if (inRes.ok) {
				const d = await inRes.json();
				this.inbound = d.delegations || [];
			}
			if (usersRes.ok) {
				const d = await usersRes.json();
				this.users = d.users || [];
			}
		} catch {
			this.error = "Failed to load delegation data";
		}

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

	private getWeightForAuthority(authority: string): number {
		return this.outbound
			.filter(d => d.authority === authority && d.state === "active")
			.reduce((sum, d) => sum + d.weight, 0);
	}

	private getDelegationsForAuthority(authority: string): Delegation[] {
		return this.outbound.filter(d => d.authority === authority && d.state !== "revoked");
	}

	private getInboundForAuthority(authority: string): Delegation[] {
		return this.inbound.filter(d => d.authority === authority && d.state === "active");
	}

	private getUserName(did: string): string {
		const u = this.users.find(u => u.did === did);
		return u?.displayName || u?.username || did.slice(0, 16) + "...";
	}

	private async createDelegation() {
		if (!this.modalDelegate) return;
		const headers = { ...this.getAuthHeaders(), "Content-Type": "application/json" };
		const authBase = this.getAuthBase();

		try {
			let res: Response;
			if (this.editingId) {
				// PATCH existing delegation
				const body = JSON.stringify({
					weight: this.modalWeight / 100,
					maxDepth: this.modalMaxDepth,
					retainAuthority: this.modalRetainAuthority,
				});
				res = await fetch(`${authBase}/api/delegations/${this.editingId}`, { method: "PATCH", headers, body });
			} else {
				// POST new delegation
				const body = JSON.stringify({
					delegateDid: this.modalDelegate,
					authority: this.modalAuthority,
					weight: this.modalWeight / 100,
					spaceSlug: this.space,
					maxDepth: this.modalMaxDepth,
					retainAuthority: this.modalRetainAuthority,
				});
				res = await fetch(`${authBase}/api/delegations`, { method: "POST", headers, body });
			}

			const data = await res.json();

			if (!res.ok) {
				this.error = data.error || "Failed to save delegation";
				this.render();
				return;
			}

			this.showModal = false;
			this.editingId = null;
			this.error = "";
			await this.loadData();

			// Dispatch cross-component sync event
			this.dispatchEvent(new CustomEvent("delegations-updated", {
				bubbles: true, composed: true,
				detail: { space: this.space },
			}));
		} catch {
			this.error = "Network error saving delegation";
			this.render();
		}
	}

	private async updateDelegation(id: string, updates: Record<string, unknown>) {
		const headers = { ...this.getAuthHeaders(), "Content-Type": "application/json" };
		const authBase = this.getAuthBase();

		try {
			const res = await fetch(`${authBase}/api/delegations/${id}`, {
				method: "PATCH",
				headers,
				body: JSON.stringify(updates),
			});

			if (!res.ok) {
				const data = await res.json();
				this.error = data.error || "Failed to update delegation";
				this.render();
				return;
			}
			await this.loadData();
			this.dispatchEvent(new CustomEvent("delegations-updated", { bubbles: true, composed: true, detail: { space: this.space } }));
		} catch {
			this.error = "Network error";
			this.render();
		}
	}

	private async revokeDelegation(id: string) {
		const headers = this.getAuthHeaders();
		const authBase = this.getAuthBase();

		try {
			const res = await fetch(`${authBase}/api/delegations/${id}`, { method: "DELETE", headers });
			if (!res.ok) {
				const data = await res.json();
				this.error = data.error || "Failed to revoke delegation";
				this.render();
				return;
			}
			await this.loadData();
			this.dispatchEvent(new CustomEvent("delegations-updated", { bubbles: true, composed: true, detail: { space: this.space } }));
		} catch {
			this.error = "Network error";
			this.render();
		}
	}

	private renderAuthorityBar(authority: string): string {
		const total = this.getWeightForAuthority(authority);
		const pct = Math.round(total * 100);
		const delegations = this.getDelegationsForAuthority(authority);
		const inboundCount = this.getInboundForAuthority(authority).length;
		const icon = AUTHORITY_ICONS[authority] || "";

		return `
		<div class="authority-row">
			<div class="authority-header">
				<span class="authority-icon">${icon}</span>
				<span class="authority-name">${DM_AUTHORITY_DISPLAY[authority]?.label || authority}</span>
				<span class="authority-pct">${pct}% delegated</span>
				${inboundCount > 0 ? `<span class="authority-inbound">${inboundCount} received</span>` : ""}
				<button class="btn-add" data-add-authority="${authority}" title="Add delegation">+</button>
			</div>
			<div class="authority-bar-track">
				<div class="authority-bar-fill" style="width:${pct}%;background:${pct > 90 ? '#ef4444' : '#a78bfa'}"></div>
			</div>
			${delegations.length > 0 ? `
			<div class="delegation-list">
				${delegations.map(d => `
				<div class="delegation-item ${d.state === 'paused' ? 'paused' : ''}">
					<span class="delegation-name">${this.esc(this.getUserName(d.delegateDid))}</span>
					<span class="delegation-weight">${Math.round(d.weight * 100)}%</span>
					<span class="delegation-state">${d.state}</span>
					<button class="btn-sm btn-edit" data-edit="${d.id}" data-edit-auth="${d.authority}" data-edit-did="${d.delegateDid}" data-edit-weight="${Math.round(d.weight * 100)}" data-edit-depth="${d.maxDepth}" data-edit-retain="${d.retainAuthority}" title="Edit">\u270E</button>
					${d.state === 'active' ? `
						<button class="btn-sm btn-pause" data-pause="${d.id}" title="Pause">||</button>
					` : d.state === 'paused' ? `
						<button class="btn-sm btn-resume" data-resume="${d.id}" title="Resume">\u25B6</button>
					` : ""}
					<button class="btn-sm btn-revoke" data-revoke="${d.id}" title="Revoke">\u2715</button>
				</div>`).join("")}
			</div>` : ""}
		</div>`;
	}

	private renderModal(): string {
		if (!this.showModal) return "";

		const currentTotal = this.getWeightForAuthority(this.modalAuthority);
		const maxWeight = Math.round((1.0 - currentTotal) * 100);

		return `
		<div class="modal-overlay" id="modal-overlay">
			<div class="modal">
				<div class="modal-header">
					<span class="modal-title">${this.editingId ? "Edit" : "New"} Delegation</span>
					<button class="modal-close" id="modal-close">\u2715</button>
				</div>
				<div class="modal-body">
					<label class="field-label">Authority</label>
					<select class="field-select" id="modal-authority">
						${AUTHORITIES.map(a => `<option value="${a}" ${this.modalAuthority === a ? "selected" : ""}>${AUTHORITY_ICONS[a]} ${DM_AUTHORITY_DISPLAY[a]?.label || a}</option>`).join("")}
					</select>

					<label class="field-label">Delegate</label>
					<select class="field-select" id="modal-delegate">
						<option value="">Select a member...</option>
						${this.users.map(u => `<option value="${u.did}" ${this.modalDelegate === u.did ? "selected" : ""}>${this.esc(u.displayName || u.username)}</option>`).join("")}
					</select>

					<label class="field-label" id="weight-label">Weight: ${this.modalWeight}%</label>
					<input type="range" min="1" max="${Math.max(maxWeight, 1)}" value="${this.modalWeight}" class="field-slider" id="modal-weight">
					<div class="field-hint">Available: ${maxWeight}% of ${DM_AUTHORITY_DISPLAY[this.modalAuthority]?.label || this.modalAuthority}</div>

					<label class="field-label" id="depth-label">Re-delegation depth: ${this.modalMaxDepth}</label>
					<input type="range" min="0" max="5" value="${this.modalMaxDepth}" class="field-slider" id="modal-depth">

					<label class="field-check">
						<input type="checkbox" id="modal-retain" ${this.modalRetainAuthority ? "checked" : ""}>
						Retain authority alongside delegate
					</label>

					${this.error ? `<div class="modal-error">${this.esc(this.error)}</div>` : ""}
				</div>
				<div class="modal-footer">
					<button class="btn-cancel" id="modal-cancel">Cancel</button>
					<button class="btn-confirm" id="modal-confirm">${this.editingId ? "Update" : "Delegate"}</button>
				</div>
			</div>
		</div>`;
	}

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

			.dm-header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
			.dm-title { font-size: 15px; font-weight: 600; }
			.dm-subtitle { font-size: 12px; color: var(--rs-text-muted); }

			.authority-row { margin-bottom: 16px; }
			.authority-header {
				display: flex; align-items: center; gap: 8px; margin-bottom: 6px;
			}
			.authority-icon { font-size: 16px; }
			.authority-name { font-size: 13px; font-weight: 600; text-transform: capitalize; flex: 1; }
			.authority-pct { font-size: 12px; color: var(--rs-text-muted); }
			.authority-inbound {
				font-size: 11px; color: #a78bfa; background: rgba(167,139,250,0.1);
				padding: 2px 6px; border-radius: 4px;
			}
			.btn-add {
				width: 24px; height: 24px; border: 1px solid var(--rs-input-border); border-radius: 6px;
				background: var(--rs-input-bg); color: var(--rs-text-primary); cursor: pointer;
				font-size: 14px; display: flex; align-items: center; justify-content: center;
			}
			.btn-add:hover { border-color: #a78bfa; color: #a78bfa; }

			.authority-bar-track {
				height: 6px; background: var(--rs-bg-surface-raised, #1a1a2e); border-radius: 3px;
				overflow: hidden; margin-bottom: 8px;
			}
			.authority-bar-fill {
				height: 100%; border-radius: 3px; transition: width 0.3s;
			}

			.delegation-list { display: flex; flex-direction: column; gap: 4px; }
			.delegation-item {
				display: flex; align-items: center; gap: 8px; padding: 6px 10px;
				background: var(--rs-bg-surface); border: 1px solid var(--rs-border); border-radius: 8px;
				font-size: 12px;
			}
			.delegation-item.paused { opacity: 0.6; }
			.delegation-name { flex: 1; font-weight: 500; }
			.delegation-weight { color: #a78bfa; font-weight: 600; min-width: 36px; text-align: right; }
			.delegation-state {
				font-size: 10px; text-transform: uppercase; color: var(--rs-text-muted);
				padding: 1px 5px; border-radius: 3px; background: var(--rs-bg-surface-raised, #1a1a2e);
			}

			.btn-sm {
				width: 22px; height: 22px; border: none; border-radius: 4px;
				background: transparent; color: var(--rs-text-muted); cursor: pointer;
				font-size: 11px; display: flex; align-items: center; justify-content: center;
			}
			.btn-sm:hover { background: var(--rs-bg-hover); }
			.btn-revoke:hover { color: #ef4444; }
			.btn-pause:hover { color: #f59e0b; }
			.btn-resume:hover { color: #22c55e; }
			.btn-edit:hover { color: #a78bfa; }

			.modal-overlay {
				position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 100;
				display: flex; align-items: center; justify-content: center;
			}
			.modal {
				background: var(--rs-bg-surface); border: 1px solid var(--rs-border-strong);
				border-radius: 12px; width: 380px; max-width: 95vw;
			}
			.modal-header {
				display: flex; align-items: center; padding: 14px 16px;
				border-bottom: 1px solid var(--rs-border);
			}
			.modal-title { font-size: 14px; font-weight: 600; flex: 1; }
			.modal-close {
				background: none; border: none; color: var(--rs-text-muted); cursor: pointer; font-size: 16px;
			}
			.modal-body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
			.modal-footer {
				display: flex; gap: 8px; justify-content: flex-end; padding: 12px 16px;
				border-top: 1px solid var(--rs-border);
			}

			.field-label { font-size: 12px; font-weight: 600; color: var(--rs-text-muted); }
			.field-select, .field-input {
				width: 100%; padding: 8px 10px; border: 1px solid var(--rs-input-border);
				border-radius: 8px; background: var(--rs-input-bg); color: var(--rs-input-text);
				font-size: 13px; outline: none;
			}
			.field-select:focus, .field-input:focus { border-color: #a78bfa; }
			.field-slider {
				width: 100%; accent-color: #a78bfa;
			}
			.field-hint { font-size: 11px; color: var(--rs-text-muted); }
			.field-check {
				display: flex; align-items: center; gap: 8px; font-size: 12px;
				color: var(--rs-text-secondary); cursor: pointer;
			}
			.field-check input { accent-color: #a78bfa; }

			.modal-error { font-size: 12px; color: #ef4444; padding: 6px 10px; background: rgba(239,68,68,0.1); border-radius: 6px; }

			.btn-cancel {
				padding: 6px 14px; border: 1px solid var(--rs-border); border-radius: 8px;
				background: transparent; color: var(--rs-text-muted); cursor: pointer; font-size: 13px;
			}
			.btn-confirm {
				padding: 6px 14px; border: none; border-radius: 8px;
				background: #a78bfa; color: #fff; cursor: pointer; font-size: 13px; font-weight: 600;
			}
			.btn-confirm:hover { background: #8b5cf6; }

			.loading { text-align: center; color: var(--rs-text-muted); padding: 40px; font-size: 13px; }
			.error-msg { font-size: 12px; color: #ef4444; margin-bottom: 10px; }

			.section-title {
				font-size: 11px; font-weight: 600; color: var(--rs-text-muted); text-transform: uppercase;
				letter-spacing: 0.05em; margin: 16px 0 8px;
			}
		</style>

		${this.loading ? `<div class="loading">Loading delegations...</div>` : `
			<div class="dm-header">
				<span class="dm-title">My Delegations</span>
				<span class="dm-subtitle">Outbound</span>
			</div>

			${this.error && !this.showModal ? `<div class="error-msg">${this.esc(this.error)}</div>` : ""}

			${AUTHORITIES.map(a => this.renderAuthorityBar(a)).join("")}

			${this.inbound.length > 0 ? `
				<div class="section-title">Received Delegations</div>
				${this.inbound.filter(d => d.state === "active").map(d => `
					<div class="delegation-item">
						<span class="delegation-name">${this.esc(this.getUserName(d.delegatorDid))}</span>
						<span class="delegation-weight">${Math.round(d.weight * 100)}%</span>
						<span class="delegation-state">${d.authority}</span>
					</div>
				`).join("")}
			` : ""}
		`}

		${this.renderModal()}
		`;

		this.attachListeners();
	}

	private attachListeners() {
		// Add delegation buttons
		this.shadow.querySelectorAll("[data-add-authority]").forEach(el => {
			el.addEventListener("click", () => {
				this.modalAuthority = (el as HTMLElement).dataset.addAuthority!;
				this.modalDelegate = "";
				this.modalWeight = 50;
				this.modalMaxDepth = 3;
				this.modalRetainAuthority = true;
				this.editingId = null;
				this.error = "";

				// Clamp default weight to available
				const currentTotal = this.getWeightForAuthority(this.modalAuthority);
				const max = Math.round((1.0 - currentTotal) * 100);
				this.modalWeight = Math.min(50, max);

				this.showModal = true;
				this.render();
			});
		});

		// Edit buttons
		this.shadow.querySelectorAll("[data-edit]").forEach(el => {
			el.addEventListener("click", () => {
				const ds = (el as HTMLElement).dataset;
				this.editingId = ds.edit!;
				this.modalAuthority = ds.editAuth!;
				this.modalDelegate = ds.editDid!;
				this.modalWeight = parseInt(ds.editWeight!) || 50;
				this.modalMaxDepth = parseInt(ds.editDepth!) || 3;
				this.modalRetainAuthority = ds.editRetain === "true";
				this.error = "";
				this.showModal = true;
				this.render();
			});
		});

		// Pause/Resume/Revoke buttons
		this.shadow.querySelectorAll("[data-pause]").forEach(el => {
			el.addEventListener("click", () => this.updateDelegation((el as HTMLElement).dataset.pause!, { state: "paused" }));
		});
		this.shadow.querySelectorAll("[data-resume]").forEach(el => {
			el.addEventListener("click", () => this.updateDelegation((el as HTMLElement).dataset.resume!, { state: "active" }));
		});
		this.shadow.querySelectorAll("[data-revoke]").forEach(el => {
			el.addEventListener("click", () => {
				if (confirm("Revoke this delegation?")) {
					this.revokeDelegation((el as HTMLElement).dataset.revoke!);
				}
			});
		});

		// Modal listeners
		if (this.showModal) {
			this.shadow.getElementById("modal-close")?.addEventListener("click", () => {
				this.showModal = false;
				this.error = "";
				this.render();
			});
			this.shadow.getElementById("modal-overlay")?.addEventListener("click", (e) => {
				if ((e.target as HTMLElement).id === "modal-overlay") {
					this.showModal = false;
					this.error = "";
					this.render();
				}
			});
			this.shadow.getElementById("modal-cancel")?.addEventListener("click", () => {
				this.showModal = false;
				this.error = "";
				this.render();
			});
			this.shadow.getElementById("modal-confirm")?.addEventListener("click", () => {
				this.createDelegation();
			});
			this.shadow.getElementById("modal-authority")?.addEventListener("change", (e) => {
				this.modalAuthority = (e.target as HTMLSelectElement).value;
				const currentTotal = this.getWeightForAuthority(this.modalAuthority);
				const max = Math.round((1.0 - currentTotal) * 100);
				this.modalWeight = Math.min(this.modalWeight, max);
				this.render();
			});
			this.shadow.getElementById("modal-delegate")?.addEventListener("change", (e) => {
				this.modalDelegate = (e.target as HTMLSelectElement).value;
			});
			this.shadow.getElementById("modal-weight")?.addEventListener("input", (e) => {
				this.modalWeight = parseInt((e.target as HTMLInputElement).value);
				const label = this.shadow.getElementById("weight-label");
				if (label) label.textContent = `Weight: ${this.modalWeight}%`;
			});
			this.shadow.getElementById("modal-depth")?.addEventListener("input", (e) => {
				this.modalMaxDepth = parseInt((e.target as HTMLInputElement).value);
				const label = this.shadow.getElementById("depth-label");
				if (label) label.textContent = `Re-delegation depth: ${this.modalMaxDepth}`;
			});
			this.shadow.getElementById("modal-retain")?.addEventListener("change", (e) => {
				this.modalRetainAuthority = (e.target as HTMLInputElement).checked;
			});
		}
	}

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

customElements.define("folk-delegation-manager", FolkDelegationManager);
