/**
 * <rstack-space-settings> — Space settings slide-out panel.
 *
 * Shows members list, add member (by username or email), pending invites.
 * Only admins/owners see the full panel; others see a read-only member list.
 */

const SESSION_KEY = "encryptid_session";

interface MemberInfo {
	did: string;
	role: string;
	displayName?: string;
	joinedAt?: number;
}

function getSession(): { accessToken: string; claims: { sub: string; username?: string } } | null {
	try {
		const raw = localStorage.getItem(SESSION_KEY);
		if (!raw) return null;
		return JSON.parse(raw);
	} catch { return null; }
}

function getToken(): string | null {
	return getSession()?.accessToken || null;
}

export class RStackSpaceSettings extends HTMLElement {
	private _open = false;
	private _space = "";
	private _members: MemberInfo[] = [];
	private _ownerDID = "";
	private _myRole: string = "viewer";
	private _isOwner = false;
	private _invites: any[] = [];
	private _addMode: "username" | "email" = "username";
	private _lookupResult: { did: string; username: string; displayName: string } | null = null;
	private _lookupError = "";

	static define() {
		if (!customElements.get("rstack-space-settings")) {
			customElements.define("rstack-space-settings", RStackSpaceSettings);
		}
	}

	static get observedAttributes() { return ["space"]; }

	attributeChangedCallback(name: string, _old: string, val: string) {
		if (name === "space") this._space = val;
	}

	connectedCallback() {
		this._space = this.getAttribute("space") || "";
		this.attachShadow({ mode: "open" });
		this._render();
	}

	open() {
		this._open = true;
		this._loadData();
		this._render();
	}

	close() {
		this._open = false;
		this._render();
	}

	toggle() {
		if (this._open) this.close(); else this.open();
	}

	private async _loadData() {
		if (!this._space) return;

		const session = getSession();
		const token = getToken();

		// Load community data from WS-synced doc (via global)
		const sync = (window as any).__rspaceCommunitySync;
		if (sync?.doc) {
			const data = sync.doc;
			this._ownerDID = data.meta?.ownerDID || "";
			this._members = [];
			if (data.members) {
				for (const [did, m] of Object.entries(data.members)) {
					const member = m as MemberInfo;
					this._members.push({ did, role: member.role, displayName: member.displayName, joinedAt: member.joinedAt });
				}
			}
		} else {
			// Fallback: fetch from API
			try {
				const res = await fetch(`/${this._space}/rspace/api/meta`, {
					headers: token ? { "Authorization": `Bearer ${token}` } : {},
				});
				if (res.ok) {
					const json = await res.json();
					this._ownerDID = json.meta?.ownerDID || "";
					if (json.meta?.members) {
						this._members = [];
						for (const [did, m] of Object.entries(json.meta.members)) {
							const member = m as MemberInfo;
							this._members.push({ did, role: member.role, displayName: member.displayName });
						}
					}
				}
			} catch {}
		}

		// Determine my role
		if (session?.claims?.sub) {
			this._isOwner = session.claims.sub === this._ownerDID;
			const myMember = this._members.find(m => m.did === session.claims.sub);
			this._myRole = this._isOwner ? "admin" : (myMember?.role || "viewer");
		}

		// Load invites (admin only)
		if (this._isAdmin && token) {
			try {
				const res = await fetch(`/${this._space}/invites`, {
					headers: { "Authorization": `Bearer ${token}` },
				});
				if (res.ok) {
					const json = await res.json();
					this._invites = json.invites || [];
				}
			} catch {}
		}

		this._render();
	}

	private get _isAdmin(): boolean {
		return this._isOwner || this._myRole === "admin";
	}

	private _render() {
		if (!this.shadowRoot) return;

		if (!this._open) {
			this.shadowRoot.innerHTML = "";
			return;
		}

		const roleOptions = (currentRole: string) => {
			const roles = ["viewer", "member", "moderator", "admin"];
			return roles.map(r => `<option value="${r}" ${r === currentRole ? "selected" : ""}>${r}</option>`).join("");
		};

		const membersHTML = this._members.map(m => {
			const isOwnerRow = m.did === this._ownerDID;
			const displayName = m.displayName || m.did.slice(0, 16) + "…";
			const initial = displayName.charAt(0).toUpperCase();
			const roleBadge = isOwnerRow
				? `<span class="role-badge role-owner">Owner</span>`
				: `<span class="role-badge role-${m.role}">${m.role}</span>`;

			let controls = "";
			if (this._isAdmin && !isOwnerRow) {
				controls = `
					<select class="role-select" data-did="${m.did}">
						${roleOptions(m.role)}
					</select>
					<button class="remove-btn" data-did="${m.did}" title="Remove member">&times;</button>
				`;
			}

			return `
				<div class="member-row">
					<div class="member-avatar">${initial}</div>
					<div class="member-info">
						<div class="member-name">${this._esc(displayName)}</div>
						${roleBadge}
					</div>
					<div class="member-controls">${controls}</div>
				</div>
			`;
		}).join("");

		const invitesHTML = this._invites
			.filter(inv => inv.status === "pending")
			.map(inv => {
				const expiry = new Date(inv.expiresAt).toLocaleDateString();
				return `
					<div class="invite-row">
						<div class="invite-info">
							<span class="invite-email">${this._esc(inv.email || "Link invite")}</span>
							<span class="invite-role">${inv.role}</span>
							<span class="invite-expiry">expires ${expiry}</span>
						</div>
						<button class="revoke-btn" data-invite-id="${inv.id}">Revoke</button>
					</div>
				`;
			}).join("") || '<div class="empty-state">No pending invites</div>';

		this.shadowRoot.innerHTML = `
			<style>${PANEL_CSS}</style>
			<div class="overlay" id="overlay"></div>
			<div class="panel">
				<div class="panel-header">
					<h2>Space Settings</h2>
					<button class="close-btn" id="close-btn">&times;</button>
				</div>

				<div class="panel-content">
					<section class="section">
						<h3>Members <span class="count">${this._members.length}</span></h3>
						<div class="members-list">${membersHTML}</div>
					</section>

					${this._isAdmin ? `
					<section class="section">
						<h3>Add Member</h3>
						<div class="add-toggle">
							<button class="toggle-btn ${this._addMode === "username" ? "active" : ""}" data-mode="username">By Username</button>
							<button class="toggle-btn ${this._addMode === "email" ? "active" : ""}" data-mode="email">By Email</button>
						</div>

						${this._addMode === "username" ? `
						<div class="add-form">
							<input type="text" class="input" id="add-username" placeholder="Username…" />
							${this._lookupResult ? `<div class="lookup-result">Found: <strong>${this._esc(this._lookupResult.displayName)}</strong> (@${this._esc(this._lookupResult.username)})</div>` : ""}
							${this._lookupError ? `<div class="error-msg">${this._esc(this._lookupError)}</div>` : ""}
							<div class="add-row">
								<select class="input role-input" id="add-role">
									<option value="member">member</option>
									<option value="viewer">viewer</option>
									<option value="moderator">moderator</option>
									<option value="admin">admin</option>
								</select>
								<button class="add-btn" id="add-by-username">Add</button>
							</div>
						</div>
						` : `
						<div class="add-form">
							<input type="email" class="input" id="add-email" placeholder="Email address…" />
							<div class="add-row">
								<select class="input role-input" id="add-email-role">
									<option value="member">member</option>
									<option value="viewer">viewer</option>
									<option value="moderator">moderator</option>
									<option value="admin">admin</option>
								</select>
								<button class="add-btn" id="add-by-email">Send Invite</button>
							</div>
						</div>
						`}
					</section>

					<section class="section">
						<h3>Pending Invites</h3>
						<div class="invites-list">${invitesHTML}</div>
					</section>
					` : ""}
				</div>
			</div>
		`;

		this._bindEvents();
	}

	private _bindEvents() {
		const sr = this.shadowRoot!;

		sr.getElementById("close-btn")?.addEventListener("click", () => this.close());
		sr.getElementById("overlay")?.addEventListener("click", () => this.close());

		// Toggle add mode
		sr.querySelectorAll(".toggle-btn").forEach(btn => {
			btn.addEventListener("click", () => {
				this._addMode = (btn as HTMLElement).dataset.mode as "username" | "email";
				this._lookupResult = null;
				this._lookupError = "";
				this._render();
			});
		});

		// Username lookup with debounce
		const usernameInput = sr.getElementById("add-username") as HTMLInputElement;
		if (usernameInput) {
			let debounce: ReturnType<typeof setTimeout>;
			usernameInput.addEventListener("input", () => {
				clearTimeout(debounce);
				this._lookupResult = null;
				this._lookupError = "";
				debounce = setTimeout(() => this._lookupUser(usernameInput.value), 300);
			});
		}

		// Add by username
		sr.getElementById("add-by-username")?.addEventListener("click", () => this._addByUsername());

		// Add by email
		sr.getElementById("add-by-email")?.addEventListener("click", () => this._addByEmail());

		// Role changes
		sr.querySelectorAll(".role-select").forEach(sel => {
			sel.addEventListener("change", (e) => {
				const target = e.target as HTMLSelectElement;
				this._changeRole(target.dataset.did!, target.value);
			});
		});

		// Remove member
		sr.querySelectorAll(".remove-btn").forEach(btn => {
			btn.addEventListener("click", () => {
				const did = (btn as HTMLElement).dataset.did!;
				this._removeMember(did);
			});
		});

		// Revoke invite
		sr.querySelectorAll(".revoke-btn").forEach(btn => {
			btn.addEventListener("click", () => {
				const id = (btn as HTMLElement).dataset.inviteId!;
				this._revokeInvite(id);
			});
		});
	}

	private async _lookupUser(username: string) {
		if (!username || username.length < 2) return;
		const token = getToken();
		if (!token) return;

		try {
			const res = await fetch(`https://auth.rspace.online/api/users/lookup?username=${encodeURIComponent(username)}`, {
				headers: { "Authorization": `Bearer ${token}` },
			});
			if (res.ok) {
				this._lookupResult = await res.json();
				this._lookupError = "";
			} else {
				this._lookupResult = null;
				this._lookupError = username.length > 2 ? "User not found" : "";
			}
		} catch {
			this._lookupError = "Lookup failed";
		}
		this._render();
	}

	private async _addByUsername() {
		const sr = this.shadowRoot!;
		const input = sr.getElementById("add-username") as HTMLInputElement;
		const roleSelect = sr.getElementById("add-role") as HTMLSelectElement;
		if (!input?.value) return;

		const token = getToken();
		if (!token) return;

		try {
			const res = await fetch(`/${this._space}/members/add`, {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
					"Authorization": `Bearer ${token}`,
				},
				body: JSON.stringify({ username: input.value, role: roleSelect.value }),
			});
			if (res.ok) {
				input.value = "";
				this._lookupResult = null;
				this._loadData();
			} else {
				const err = await res.json();
				this._lookupError = err.error || "Failed to add member";
				this._render();
			}
		} catch {
			this._lookupError = "Network error";
			this._render();
		}
	}

	private async _addByEmail() {
		const sr = this.shadowRoot!;
		const input = sr.getElementById("add-email") as HTMLInputElement;
		const roleSelect = sr.getElementById("add-email-role") as HTMLSelectElement;
		if (!input?.value) return;

		const token = getToken();
		if (!token) return;

		try {
			const res = await fetch(`/${this._space}/invite`, {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
					"Authorization": `Bearer ${token}`,
				},
				body: JSON.stringify({ email: input.value, role: roleSelect.value }),
			});
			if (res.ok) {
				input.value = "";
				this._loadData();
			}
		} catch {}
	}

	private async _changeRole(did: string, newRole: string) {
		const token = getToken();
		if (!token) return;

		try {
			await fetch(`/${this._space}/members/${encodeURIComponent(did)}`, {
				method: "PATCH",
				headers: {
					"Content-Type": "application/json",
					"Authorization": `Bearer ${token}`,
				},
				body: JSON.stringify({ role: newRole }),
			});
			this._loadData();
		} catch {}
	}

	private async _removeMember(did: string) {
		const token = getToken();
		if (!token) return;

		try {
			await fetch(`/${this._space}/members/${encodeURIComponent(did)}`, {
				method: "DELETE",
				headers: { "Authorization": `Bearer ${token}` },
			});
			this._loadData();
		} catch {}
	}

	private async _revokeInvite(id: string) {
		const token = getToken();
		if (!token) return;

		try {
			await fetch(`https://auth.rspace.online/api/spaces/${this._space}/invites/${id}/revoke`, {
				method: "POST",
				headers: { "Authorization": `Bearer ${token}` },
			});
			this._loadData();
		} catch {}
	}

	private _esc(s: string): string {
		return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
	}
}

const PANEL_CSS = `
:host {
	display: contents;
}

.overlay {
	position: fixed;
	inset: 0;
	background: rgba(0, 0, 0, 0.5);
	z-index: 9998;
	animation: fadeIn 0.2s ease;
}

.panel {
	position: fixed;
	top: 0;
	right: 0;
	bottom: 0;
	width: min(380px, 90vw);
	background: #1e293b;
	border-left: 1px solid rgba(255,255,255,0.1);
	z-index: 9999;
	display: flex;
	flex-direction: column;
	animation: slideIn 0.25s ease;
	color: #e2e8f0;
	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

@keyframes slideIn {
	from { transform: translateX(100%); }
	to { transform: translateX(0); }
}
@keyframes fadeIn {
	from { opacity: 0; }
	to { opacity: 1; }
}

.panel-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 16px 20px;
	border-bottom: 1px solid rgba(255,255,255,0.08);
}

.panel-header h2 {
	margin: 0;
	font-size: 1.1rem;
	font-weight: 600;
	background: linear-gradient(135deg, #14b8a6, #22d3ee);
	-webkit-background-clip: text;
	-webkit-text-fill-color: transparent;
	background-clip: text;
}

.close-btn {
	background: none;
	border: none;
	color: #64748b;
	font-size: 1.5rem;
	cursor: pointer;
	padding: 4px 8px;
	border-radius: 4px;
	line-height: 1;
}
.close-btn:hover { color: #e2e8f0; background: rgba(255,255,255,0.08); }

.panel-content {
	flex: 1;
	overflow-y: auto;
	padding: 0 20px 20px;
}

.section {
	padding-top: 16px;
}

.section h3 {
	font-size: 0.82rem;
	font-weight: 700;
	color: #94a3b8;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	margin: 0 0 10px;
}

.count {
	font-weight: 400;
	color: #64748b;
	font-size: 0.75rem;
	margin-left: 4px;
}

/* Members */
.members-list {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.member-row {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 8px 10px;
	border-radius: 8px;
	transition: background 0.15s;
}
.member-row:hover { background: rgba(255,255,255,0.04); }

.member-avatar {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	background: rgba(20,184,166,0.15);
	color: #14b8a6;
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 700;
	font-size: 0.8rem;
	flex-shrink: 0;
}

.member-info {
	flex: 1;
	min-width: 0;
}

.member-name {
	font-size: 0.85rem;
	font-weight: 500;
	color: #e2e8f0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.role-badge {
	display: inline-block;
	font-size: 0.65rem;
	font-weight: 700;
	padding: 1px 6px;
	border-radius: 9999px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.role-owner { background: rgba(124,58,237,0.2); color: #a78bfa; }
.role-admin { background: rgba(239,68,68,0.15); color: #f87171; }
.role-moderator { background: rgba(245,158,11,0.15); color: #fbbf24; }
.role-member { background: rgba(20,184,166,0.15); color: #14b8a6; }
.role-viewer { background: rgba(148,163,184,0.15); color: #94a3b8; }

.member-controls {
	display: flex;
	align-items: center;
	gap: 6px;
	flex-shrink: 0;
}

.role-select {
	background: rgba(255,255,255,0.06);
	border: 1px solid rgba(255,255,255,0.1);
	color: #e2e8f0;
	border-radius: 6px;
	padding: 3px 6px;
	font-size: 0.72rem;
	cursor: pointer;
}
.role-select:focus { outline: none; border-color: #14b8a6; }

.remove-btn {
	background: none;
	border: none;
	color: #64748b;
	font-size: 1.1rem;
	cursor: pointer;
	padding: 2px 6px;
	border-radius: 4px;
	line-height: 1;
}
.remove-btn:hover { color: #f87171; background: rgba(239,68,68,0.1); }

/* Add member */
.add-toggle {
	display: flex;
	gap: 4px;
	margin-bottom: 10px;
}

.toggle-btn {
	flex: 1;
	padding: 6px 10px;
	background: rgba(255,255,255,0.04);
	border: 1px solid rgba(255,255,255,0.08);
	color: #94a3b8;
	border-radius: 6px;
	font-size: 0.78rem;
	cursor: pointer;
	transition: all 0.15s;
}
.toggle-btn.active {
	background: rgba(20,184,166,0.1);
	border-color: rgba(20,184,166,0.3);
	color: #14b8a6;
}

.add-form {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.input {
	background: rgba(255,255,255,0.06);
	border: 1px solid rgba(255,255,255,0.1);
	color: #e2e8f0;
	border-radius: 8px;
	padding: 8px 12px;
	font-size: 0.85rem;
	width: 100%;
	box-sizing: border-box;
}
.input:focus { outline: none; border-color: #14b8a6; }
.input::placeholder { color: #64748b; }

.add-row {
	display: flex;
	gap: 8px;
}

.role-input {
	flex: 0 0 auto;
	width: auto;
	padding: 8px 10px;
}

.add-btn {
	flex-shrink: 0;
	padding: 8px 16px;
	background: linear-gradient(135deg, #14b8a6, #0d9488);
	border: none;
	color: white;
	border-radius: 8px;
	font-size: 0.82rem;
	font-weight: 600;
	cursor: pointer;
	transition: opacity 0.15s;
}
.add-btn:hover { opacity: 0.9; }

.lookup-result {
	font-size: 0.78rem;
	color: #14b8a6;
	padding: 4px 0;
}

.error-msg {
	font-size: 0.78rem;
	color: #f87171;
	padding: 4px 0;
}

/* Invites */
.invites-list {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.invite-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 8px 10px;
	border-radius: 8px;
	background: rgba(255,255,255,0.02);
}

.invite-info {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.invite-email {
	font-size: 0.82rem;
	color: #e2e8f0;
}

.invite-role {
	font-size: 0.7rem;
	color: #14b8a6;
}

.invite-expiry {
	font-size: 0.65rem;
	color: #64748b;
}

.revoke-btn {
	background: rgba(239,68,68,0.1);
	border: 1px solid rgba(239,68,68,0.2);
	color: #f87171;
	border-radius: 6px;
	padding: 4px 10px;
	font-size: 0.72rem;
	cursor: pointer;
	transition: all 0.15s;
}
.revoke-btn:hover { background: rgba(239,68,68,0.2); }

.empty-state {
	font-size: 0.8rem;
	color: #64748b;
	padding: 12px 0;
	text-align: center;
}
`;
