<script lang="ts">
	import {
		Button,
		Modal,
		Input,
		Select,
		Avatar,
	} from "$lib/components/ui";
	import { toasts } from "$lib/stores/toast.svelte";
	import type { SupabaseClient } from "@supabase/supabase-js";
	import type { Database } from "$lib/supabase/types";
	import * as m from "$lib/paraglide/messages";

	const INVITE_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; // 7 days

	interface ProfileData {
		id: string;
		email: string;
		full_name: string | null;
		avatar_url: string | null;
	}

	interface Member {
		id: string;
		user_id: string;
		role: string;
		role_id: string | null;
		invited_at: string;
		profiles: ProfileData | ProfileData[] | null;
	}

	interface OrgRole {
		id: string;
		org_id: string;
		name: string;
		color: string;
		permissions: string[];
		is_default: boolean;
		is_system: boolean;
		position: number;
	}

	interface Invite {
		id: string;
		email: string;
		role: string;
		role_id: string | null;
		token: string;
		expires_at: string;
		created_at: string;
	}

	interface Props {
		supabase: SupabaseClient<Database>;
		orgId: string;
		userId: string;
		members: Member[];
		roles: OrgRole[];
		invites: Invite[];
	}

	let {
		supabase,
		orgId,
		userId,
		members = $bindable(),
		roles,
		invites = $bindable(),
	}: Props = $props();

	let showInviteModal = $state(false);
	let inviteEmail = $state("");
	let inviteRole = $state("editor");
	let isSendingInvite = $state(false);
	let showMemberModal = $state(false);
	let selectedMember = $state<Member | null>(null);
	let selectedMemberRole = $state("");

	async function sendInvite() {
		if (!inviteEmail.trim()) return;
		isSendingInvite = true;

		const email = inviteEmail.toLowerCase().trim();

		// Delete any existing invite for this email first (handles 409 conflict)
		await supabase
			.from("org_invites")
			.delete()
			.eq("org_id", orgId)
			.eq("email", email);

		const { data: invite, error } = await supabase
			.from("org_invites")
			.insert({
				org_id: orgId,
				email,
				role: inviteRole,
				invited_by: userId,
				expires_at: new Date(
					Date.now() + INVITE_EXPIRY_MS,
				).toISOString(),
			})
			.select()
			.single();

		if (!error && invite) {
			invites = invites.filter((i) => i.email !== email);
			invites = [...invites, invite as Invite];
			inviteEmail = "";
			showInviteModal = false;
		} else if (error) {
			toasts.error(m.toast_error_invite({ error: error.message }));
		}
		isSendingInvite = false;
	}

	async function cancelInvite(inviteId: string) {
		await supabase.from("org_invites").delete().eq("id", inviteId);
		invites = invites.filter((i) => i.id !== inviteId);
	}

	function openMemberModal(member: Member) {
		selectedMember = member;
		selectedMemberRole = member.role;
		showMemberModal = true;
	}

	async function updateMemberRole() {
		if (!selectedMember) return;
		const { error } = await supabase
			.from("org_members")
			.update({ role: selectedMemberRole })
			.eq("id", selectedMember.id);

		if (error) {
			toasts.error(m.toast_error_update_role());
			return;
		}
		members = members.map((m) =>
			m.id === selectedMember!.id
				? { ...m, role: selectedMemberRole }
				: m,
		);
		showMemberModal = false;
	}

	async function removeMember() {
		if (!selectedMember) return;
		const rp = selectedMember.profiles;
		const prof = Array.isArray(rp) ? rp[0] : rp;
		if (
			!confirm(
				`Remove ${prof?.full_name || prof?.email || "this member"} from the organization?`,
			)
		)
			return;

		const { error } = await supabase
			.from("org_members")
			.delete()
			.eq("id", selectedMember.id);
		if (error) {
			toasts.error(m.toast_error_remove_member());
			return;
		}
		members = members.filter((m) => m.id !== selectedMember!.id);
		showMemberModal = false;
	}
</script>

<div class="space-y-4 max-w-2xl">
	<div class="flex items-center justify-between">
		<div>
			<h2 class="font-heading text-body text-white">
				{m.settings_members_title({
					count: String(members.length),
				})}
			</h2>
		</div>
		<Button size="sm" icon="person_add" onclick={() => (showInviteModal = true)}>
			{m.settings_members_invite()}
		</Button>
	</div>

	<!-- Pending Invites -->
	{#if invites.length > 0}
		<div class="bg-dark/30 border border-light/5 rounded-xl p-4">
			<h3 class="text-body-sm font-heading text-light/60 mb-3">
				{m.settings_members_pending()}
			</h3>
			<div class="space-y-2">
				{#each invites as invite}
					<div
						class="flex items-center justify-between py-2 px-3 bg-light/5 rounded-lg"
					>
						<div>
							<p class="text-body-sm text-white">{invite.email}</p>
							<p class="text-[11px] text-light/40">
								Invited as {invite.role} • Expires {new Date(
									invite.expires_at,
								).toLocaleDateString()}
							</p>
						</div>
						<div class="flex items-center gap-1.5">
							<button
								type="button"
								class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
								onclick={() =>
									navigator.clipboard.writeText(
										`${window.location.origin}/invite/${invite.token}`,
									)}
								title={m.settings_members_copy_link()}
							>
								<span class="material-symbols-rounded" style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 18;">content_copy</span>
							</button>
							<button
								type="button"
								class="p-1.5 text-light/40 hover:text-error hover:bg-error/10 rounded-lg transition-colors"
								onclick={() => cancelInvite(invite.id)}
								title="Cancel invite"
							>
								<span class="material-symbols-rounded" style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 18;">close</span>
							</button>
						</div>
					</div>
				{/each}
			</div>
		</div>
	{/if}

	<!-- Members List -->
	<div class="bg-dark/30 border border-light/5 rounded-xl overflow-hidden">
		<div class="divide-y divide-light/5">
			{#each members as member}
				{@const rawProfile = member.profiles}
				{@const profile = Array.isArray(rawProfile)
					? rawProfile[0]
					: rawProfile}
				<div
					class="flex items-center justify-between px-4 py-3 hover:bg-light/5 transition-colors"
				>
					<div class="flex items-center gap-3">
						<Avatar
							name={profile?.full_name || profile?.email || "?"}
							src={profile?.avatar_url}
							size="sm"
						/>
						<div>
							<p class="text-body-sm text-white">
								{profile?.full_name ||
									profile?.email ||
									"Unknown User"}
							</p>
							<p class="text-[11px] text-light/40">
								{profile?.email || "No email"}
							</p>
						</div>
					</div>
					<div class="flex items-center gap-2">
						<span
							class="px-2 py-0.5 text-[10px] rounded-md capitalize font-body"
							style="background-color: {roles.find(
								(r) => r.name.toLowerCase() === member.role,
							)?.color ?? '#6366f1'}20; color: {roles.find(
								(r) => r.name.toLowerCase() === member.role,
							)?.color ?? '#6366f1'}">{member.role}</span
						>
						{#if member.user_id !== userId && member.role !== "owner"}
							<button
								type="button"
								class="p-1.5 text-light/40 hover:text-white hover:bg-dark/50 rounded-lg transition-colors"
								onclick={() => openMemberModal(member)}
								title="Edit"
							>
								<span class="material-symbols-rounded" style="font-size: 18px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 18;">edit</span>
							</button>
						{/if}
					</div>
				</div>
			{/each}
		</div>
	</div>
</div>

<!-- Invite Member Modal -->
<Modal
	isOpen={showInviteModal}
	onClose={() => (showInviteModal = false)}
	title="Invite Member"
>
	<div class="space-y-4">
		<Input
			type="email"
			label="Email address"
			bind:value={inviteEmail}
			placeholder="colleague@example.com"
		/>
		<Select
			label="Role"
			bind:value={inviteRole}
			placeholder=""
			options={[
				{ value: "viewer", label: "Viewer - Can view content" },
				{
					value: "commenter",
					label: "Commenter - Can view and comment",
				},
				{
					value: "editor",
					label: "Editor - Can create and edit content",
				},
				{
					value: "admin",
					label: "Admin - Can manage members and settings",
				},
			]}
		/>
		<div class="flex justify-end gap-2 pt-2">
			<Button variant="tertiary" onclick={() => (showInviteModal = false)}
				>Cancel</Button
			>
			<Button
				onclick={sendInvite}
				loading={isSendingInvite}
				disabled={!inviteEmail.trim()}>Send Invite</Button
			>
		</div>
	</div>
</Modal>

<!-- Edit Member Modal -->
<Modal
	isOpen={showMemberModal}
	onClose={() => (showMemberModal = false)}
	title="Edit Member"
>
	{#if selectedMember}
		{@const rawP = selectedMember.profiles}
		{@const memberProfile = Array.isArray(rawP) ? rawP[0] : rawP}
		<div class="space-y-4">
			<div class="flex items-center gap-3 p-3 bg-light/5 rounded-lg">
				<div
					class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center text-primary font-medium"
				>
					{(memberProfile?.full_name ||
						memberProfile?.email ||
						"?")[0].toUpperCase()}
				</div>
				<div>
					<p class="text-light font-medium">
						{memberProfile?.full_name || "No name"}
					</p>
					<p class="text-sm text-light/50">
						{memberProfile?.email || "No email"}
					</p>
				</div>
			</div>
			<Select
				label="Role"
				bind:value={selectedMemberRole}
				placeholder=""
				options={[
					{ value: "viewer", label: "Viewer" },
					{ value: "commenter", label: "Commenter" },
					{ value: "editor", label: "Editor" },
					{ value: "admin", label: "Admin" },
				]}
			/>
			<div class="flex items-center justify-between pt-2">
				<Button variant="danger" onclick={removeMember}
					>Remove from Org</Button
				>
				<div class="flex gap-2">
					<Button
						variant="tertiary"
						onclick={() => (showMemberModal = false)}>Cancel</Button
					>
					<Button onclick={updateMemberRole}>Save</Button>
				</div>
			</div>
		</div>
	{/if}
</Modal>
