<script lang="ts">
	import { page } from '$app/stores';
	import { goto } from '$app/navigation';
	import { onMount } from 'svelte';
	import { Card, Badge, Button, Modal } from '$lib/components';
	import { api } from '$lib/api/client';
	import { updateTenantGroup, deleteTenant } from '$lib/api/admin';
	import { toast } from '$lib/stores/toast.svelte';
	import { data } from '$lib/stores/data.svelte';
	import type { Tenant } from '$lib/types';
	import TenantModal from '../TenantModal.svelte';
	import {
		Copy, ExternalLink, RefreshCw,
		Cpu, HardDrive, MemoryStick, Box, Eye, EyeOff, Activity, Globe, FileText, Key, RotateCcw, Pencil, Trash2
	} from 'lucide-svelte';

	type Probe = {
		ok: boolean;
		status: number | null;
		error: string;
		preview: string;
	};

	type RuntimeUnit = {
		activeState: string;
		subState: string;
		result: string;
	};

	type TenantHostedService = {
		Name: string;
		Runtime: string;
		Subdomain: string;
		ServiceName: string;
		State: string;
		Status: string;
		Result: string;
		Port: number | null;
		PublicService: string | null;
		ProjectName: string | null;
		LocalUrl: string | null;
		PublicUrl: string | null;
		LocalProbe: Probe;
		PublicProbe: Probe;
		RecentLogs: string;
	};

	type TenantServicesPayload = {
		hasCompose: boolean;
		hasNerdctl: boolean;
		runtime: Record<string, RuntimeUnit>;
		services: TenantHostedService[];
		composeContent: string;
	};

	let showPassword = $state(false);
	let newPassword = $state<string | null>(null);
	let resettingPassword = $state(false);
	let services = $state<TenantServicesPayload | null>(null);
	let servicesLoading = $state(true);
	let servicesError = $state<string | null>(null);

	type DiskUsage = {
		containerd_mb: number;
		buildkit_mb: number;
		nerdctl_mb: number;
		workspace_mb: number;
		volumes: Record<string, number>;
	};
	let diskUsage = $state<DiskUsage | null>(null);
	let diskUsageLoading = $state(false);
	let diskUsageError = $state<string | null>(null);

	async function fetchDiskUsage() {
		diskUsageLoading = true;
		diskUsageError = null;
		try {
			diskUsage = await api.get<DiskUsage>(`/tenants/${tenantId}/disk-usage`);
		} catch (e: any) {
			diskUsageError = e.message ?? "Failed to load disk usage";
		} finally {
			diskUsageLoading = false;
		}
	}

	async function resetPassword() {
		resettingPassword = true;
		try {
			const res = await api.post<{ message: string; password: string; url: string }>(
				`/tenants/${tenantId}/dashboard-password`
			);
			newPassword = res.password;
			await fetchTenant(); // refresh to show updated hash
		} catch (e: any) {
			toast.error(e.message ?? 'Failed to reset password');
		} finally {
			resettingPassword = false;
		}
	}

	const tenantId = $derived($page.params.id);

	let tenant = $state<Tenant | null>(null);
	let loading = $state(true);
	let error = $state<string | null>(null);
	let editOpen = $state(false);
	let editingTenant = $state<Tenant | null>(null);

	let deleteOpen = $state(false);
	let deleteConfirmName = $state('');
	let deleting = $state(false);

	async function handleDelete() {
		if (!tenant || deleteConfirmName !== tenant.name) return;
		deleting = true;
		try {
			await deleteTenant(tenant.id);
			await data.refetchTenants();
			goto('/tenants');
		} catch (e: any) {
			toast.error(e.message ?? 'Failed to delete tenant');
			deleting = false;
		}
	}

	const globalProvider = $derived.by(() => data.settings?.default_provider ?? 'codex');
	function effectiveProvider(t: Tenant): 'claude' | 'codex' {
		return (t.provider ?? globalProvider) as any;
	}
	function providerLabel(t: Tenant): string {
		return t.provider ? t.provider : `default (${effectiveProvider(t)})`;
	}

	async function fetchServices() {
		servicesLoading = true;
		servicesError = null;
		try {
			services = await api.get<TenantServicesPayload>(`/tenants/${tenantId}/services`);
		} catch (e: any) {
			servicesError = e.message ?? 'Failed to load hosted apps';
		} finally {
			servicesLoading = false;
		}
	}

	async function fetchTenant() {
		loading = true;
		error = null;
		try {
			tenant = await api.get<Tenant>(`/tenants/${tenantId}`);
		} catch (e: any) {
			error = e.message ?? 'Failed to load tenant';
		} finally {
			loading = false;
		}
	}

	async function refreshPage() {
		await Promise.all([fetchTenant(), fetchServices()]);
	}

	onMount(refreshPage);

	function copy(value: string, label = 'Copied') {
		if (navigator.clipboard) {
			navigator.clipboard.writeText(value).catch(() => copyFallback(value));
		} else {
			copyFallback(value);
		}
		toast.success(`${label} copied`);
	}

	function copyFallback(value: string) {
		const el = document.createElement('textarea');
		el.value = value;
		el.style.cssText = 'position:fixed;opacity:0';
		document.body.appendChild(el);
		el.select();
		document.execCommand('copy');
		document.body.removeChild(el);
	}

	const statusColor: Record<string, 'emerald' | 'amber' | 'rose'> = {
		active: 'emerald',
		suspended: 'amber',
		archived: 'rose'
	};

	function formatDuration(ms: number): string {
		if (ms < 60000) return `${Math.round(ms / 1000)}s`;
		const m = Math.round(ms / 60000);
		if (m < 60) return `${m}m`;
		return `${Math.floor(m / 60)}h ${m % 60}m`;
	}

	function formatDate(s: string): string {
		return new Date(s).toLocaleString();
	}

	function channelType(jid: string) {
		if (jid.startsWith('dc:')) return 'discord';
		if (jid.startsWith('tg:')) return 'telegram';
		if (jid.startsWith('sl:')) return 'slack';
		return 'whatsapp';
	}

	function unitBadgeColor(state: string, result: string): 'emerald' | 'amber' | 'rose' | 'dim' {
		if (state === 'active') return 'emerald';
		if (result === 'failed' || state === 'failed') return 'rose';
		if (state === 'activating' || state === 'reloading') return 'amber';
		return 'dim';
	}

	function probeBadgeColor(probe: Probe | null | undefined): 'emerald' | 'amber' | 'rose' | 'dim' {
		if (!probe) return 'dim';
		if (probe.ok) return 'emerald';
		if (probe.status != null) return 'amber';
		if (probe.error) return 'rose';
		return 'dim';
	}

	function probeLabel(probe: Probe | null | undefined): string {
		if (!probe) return 'unknown';
		if (probe.ok) return `ok ${probe.status ?? ''}`.trim();
		if (probe.status != null) return `http ${probe.status}`;
		return probe.error || 'down';
	}
	async function toggleHooks(tenantId: string, jid: string, enabled: boolean) {
		try {
			await updateTenantGroup(tenantId, jid, { hooks_enabled: enabled });
			await fetchTenant();
			toast.success(enabled ? 'Hooks enabled' : 'Hooks disabled');
		} catch (e: any) {
			toast.error(e.message ?? 'Failed to update hooks');
		}
	}

	async function rotateHooksToken(tenantId: string, jid: string) {
		try {
			await updateTenantGroup(tenantId, jid, { hooks_rotate: true });
			await fetchTenant();
			toast.success('Token rotated');
		} catch (e: any) {
			toast.error(e.message ?? 'Failed to rotate token');
		}
	}
</script>

<div class="page">
	{#if loading}
		<div class="center dim">Loading…</div>
	{:else if error}
		<div class="center error">{error}</div>
	{:else if tenant}
		<div class="page-header">
			<div class="page-title">
				<span class="mono">{tenant.id}</span>
				<span class="dim">· {tenant.name}</span>
			</div>
			<div class="page-actions">
				<Button
					variant="secondary"
					size="sm"
					onclick={() => {
						editingTenant = tenant;
						editOpen = true;
					}}
				>
					<Pencil size={14} /> Edit Tenant
				</Button>
				<Button
					variant="danger"
					size="sm"
					onclick={() => { deleteConfirmName = ''; deleteOpen = true; }}
				>
					<Trash2 size={14} /> Delete Tenant
				</Button>
			</div>
		</div>

		<div class="grid">

			<!-- Identity -->
			<Card title="Identity">
				<div class="detail-list">
					<div class="detail-row">
						<span class="detail-label">ID</span>
						<span class="detail-value mono">{tenant.id}</span>
					</div>
					<div class="detail-row">
						<span class="detail-label">Name</span>
						<span class="detail-value">{tenant.name}</span>
					</div>
					<div class="detail-row">
						<span class="detail-label">Status</span>
						<span class="detail-value" style="display:flex;gap:6px;flex-wrap:wrap">
							<Badge color={statusColor[tenant.status] ?? 'dim'}>{tenant.status}</Badge>
							{#if tenant.tenant_type === 'bot'}
								<Badge color="accent">bot</Badge>
							{/if}
						</span>
					</div>
					{#if tenant.email}
						<div class="detail-row">
							<span class="detail-label">Email</span>
							<span class="detail-value">{tenant.email}</span>
						</div>
					{/if}
					<div class="detail-row">
						<span class="detail-label">Provider</span>
						<span class="detail-value">
							<Badge color={effectiveProvider(tenant) === 'codex' ? 'accent' : effectiveProvider(tenant) === 'pi' ? 'purple' : 'cyan'}>
								{providerLabel(tenant)}
							</Badge>
						</span>
					</div>
					<div class="detail-row">
						<span class="detail-label">Model</span>
						<span class="detail-value mono">{tenant.model || 'default'}</span>
					</div>
					{#if effectiveProvider(tenant) === 'pi'}
					<div class="detail-row">
						<span class="detail-label">Pi Backend</span>
						<span class="detail-value mono">{tenant.pi_backend || 'anthropic (default)'}</span>
					</div>
					{/if}
					<div class="detail-row">
						<span class="detail-label">Progress</span>
						<span class="detail-value">
							<Badge color={tenant.show_progress_messages ? 'emerald' : 'dim'}>
								{tenant.show_progress_messages ? 'visible' : 'hidden'}
							</Badge>
						</span>
					</div>
					<div class="detail-row">
						<span class="detail-label">Created</span>
						<span class="detail-value dim">{formatDate(tenant.created_at)}</span>
					</div>
					{#if tenant.is_admin}
						<div class="detail-row">
							<span class="detail-label">Role</span>
							<Badge color="accent">admin</Badge>
						</div>
					{/if}
					<div class="detail-row">
						<span class="detail-label">Dashboard PW</span>
						<span class="detail-value" style="flex-direction:column;align-items:flex-start;gap:6px">
							<span style="display:flex;align-items:center;gap:6px">
								{#if tenant.dashboard_password}
									<Badge color="emerald">set</Badge>
								{:else}
									<Badge color="dim">not set</Badge>
								{/if}
								<Button variant="ghost" size="sm" loading={resettingPassword} onclick={resetPassword}>
									Reset Password
								</Button>
							</span>
							{#if newPassword}
								<span class="new-password-box">
									<span class="dim" style="font-size:var(--font-size-xs)">New password:</span>
									<span class="code-box mono">{newPassword}</span>
									<button class="copy-btn" onclick={() => copy(newPassword!, 'Password')} title="Copy">
										<Copy size={13} />
									</button>
									<button class="copy-btn" onclick={() => (newPassword = null)} title="Dismiss">✕</button>
								</span>
							{/if}
						</span>
					</div>
				</div>
			</Card>

			<!-- Discord -->
			<Card title="Discord">
				<div class="detail-list">
					<div class="detail-row">
						<span class="detail-label">Pairing Status</span>
						<span class="detail-value">
							{#if tenant.discord_user_id}
								<Badge color="emerald">paired</Badge>
							{:else if tenant.discord_pairing_code}
								<Badge color="amber">pending</Badge>
							{:else}
								<Badge color="dim">unknown</Badge>
							{/if}
						</span>
					</div>
					{#if tenant.discord_pairing_code}
						<div class="detail-row">
							<span class="detail-label">Pairing Code</span>
							<span class="detail-value">
								<span class="code-box">{tenant.discord_pairing_code}</span>
								<button class="copy-btn" onclick={() => copy(tenant!.discord_pairing_code!, 'Pairing code')} title="Copy">
									<Copy size={13} />
								</button>
								{#if tenant.discord_user_id}
									<span class="dim" style="font-size:var(--font-size-xs)">(used)</span>
								{/if}
							</span>
						</div>
					{:else if !tenant.discord_user_id}
						<div class="detail-row">
							<span class="detail-label">Pairing Code</span>
							<span class="detail-value dim">no code generated</span>
						</div>
					{/if}

					{#if tenant.discord_invite}
						<div class="detail-row">
							<span class="detail-label">Invite Link</span>
							<span class="detail-value link-row">
								<a href={tenant.discord_invite} target="_blank" class="link">{tenant.discord_invite}</a>
								<button class="copy-btn" onclick={() => copy(tenant!.discord_invite!, 'Invite link')} title="Copy">
									<Copy size={13} />
								</button>
								<a href={tenant.discord_invite} target="_blank" class="copy-btn" title="Open">
									<ExternalLink size={13} />
								</a>
							</span>
						</div>
					{:else}
						<div class="detail-row">
							<span class="detail-label">Invite Link</span>
							<span class="detail-value dim">—</span>
						</div>
					{/if}

					{#if tenant.discord_user_id}
						<div class="detail-row">
							<span class="detail-label">User ID</span>
							<span class="detail-value mono">{tenant.discord_user_id}</span>
						</div>
					{/if}

					{#if tenant.discord_category_id}
						<div class="detail-row">
							<span class="detail-label">Category ID</span>
							<span class="detail-value mono">{tenant.discord_category_id}</span>
						</div>
					{/if}
				</div>
			</Card>

			<!-- Resources -->
			<Card title="Resources">
				<div class="detail-list">
					<div class="detail-row">
						<span class="detail-label"><MemoryStick size={13} /> Memory</span>
						<span class="detail-value mono">
							{#if tenant.resources?.slice_mem_mb != null}
								{tenant.resources.slice_mem_mb} / {tenant.max_memory_mb} MB
							{:else}
								{tenant.max_memory_mb} MB limit
							{/if}
						</span>
					</div>
					<div class="detail-row">
						<span class="detail-label"><Cpu size={13} /> CPU</span>
						<span class="detail-value mono">{tenant.cpu_quota} (weight {tenant.cpu_weight})</span>
					</div>
					<div class="detail-row">
						<span class="detail-label"><HardDrive size={13} /> Disk</span>
						<span class="detail-value mono">
							{#if tenant.resources?.volume}
								{tenant.resources.volume.used_mb} / {tenant.resources.volume.used_mb + tenant.resources.volume.avail_mb} MB
							{:else}
								{tenant.max_disk_mb} MB limit
							{/if}
						</span>
					</div>
					<!-- Disk breakdown -->
					<div class="detail-row" style="flex-direction:column;align-items:flex-start;gap:8px">
						<div style="display:flex;align-items:center;gap:8px">
							<span class="detail-label" style="min-width:unset;padding-top:0">Breakdown</span>
							<Button variant="ghost" size="sm" loading={diskUsageLoading} onclick={fetchDiskUsage}>
								{diskUsage ? 'Refresh' : 'Load'}
							</Button>
						</div>
						{#if diskUsageError}
							<span class="error" style="font-size:var(--font-size-xs)">{diskUsageError}</span>
						{:else if diskUsage}
							<div class="disk-breakdown">
								<div class="disk-item">
									<span class="disk-label">containerd</span>
									<span class="disk-val mono">{diskUsage.containerd_mb} MB</span>
								</div>
								<div class="disk-item">
									<span class="disk-label">buildkit</span>
									<span class="disk-val mono">{diskUsage.buildkit_mb} MB</span>
								</div>
								<div class="disk-item">
									<span class="disk-label">nerdctl</span>
									<span class="disk-val mono">{diskUsage.nerdctl_mb} MB</span>
								</div>
								<div class="disk-item">
									<span class="disk-label">workspace</span>
									<span class="disk-val mono">{diskUsage.workspace_mb} MB</span>
								</div>
								{#each Object.entries(diskUsage.volumes) as [vol, mb]}
									<div class="disk-item disk-item-volume">
										<span class="disk-label">&#8627; {vol}</span>
										<span class="disk-val mono">{mb} MB</span>
									</div>
								{/each}
							</div>
						{/if}
					</div>
					<div class="detail-row">
						<span class="detail-label"><Box size={13} /> Containers</span>
						<span class="detail-value mono">
							{tenant.resources?.container_count ?? 0} / {tenant.max_concurrent} running
						</span>
					</div>
					{#if tenant.port_range_start != null}
						<div class="detail-row">
							<span class="detail-label">Port Range</span>
							<span class="detail-value mono">
								{tenant.port_range_start}–{tenant.port_range_start + (tenant.port_range_size ?? 10) - 1}
							</span>
						</div>
					{/if}
				</div>
			</Card>

			<!-- Running Containers -->
			<Card title="Running Containers">
				{#if tenant.resources?.containers && tenant.resources.containers.length > 0}
					<div class="containers-list">
						{#each tenant.resources.containers as c}
							<div class="container-row">
								<Badge color="emerald">up</Badge>
								{#if c.kind === 'app'}
									<Badge color="cyan">app</Badge>
								{:else}
									<Badge color="dim">agent</Badge>
								{/if}
								<span class="container-name mono">{c.name.replace(/^nanoclaw-/, '')}</span>
								<span class="dim" style="font-size:var(--font-size-xs)">{c.status}</span>
							</div>
						{/each}
					</div>
				{:else}
					<span class="dim">No containers running</span>
				{/if}
			</Card>

			<!-- Hosted Apps -->
			<Card title="Hosted Apps">
				{#if servicesLoading}
					<span class="dim">Loading hosted apps…</span>
				{:else if servicesError}
					<span class="error">{servicesError}</span>
				{:else if services}
					<div class="runtime-summary">
						{#each Object.entries(services.runtime) as [unit, info]}
							<div class="runtime-unit">
								<div class="runtime-unit-name mono">{unit.replace(/^nanoclaw-/, '').replace(/\.service$/, '')}</div>
								<div class="runtime-unit-badges">
									<Badge color={unitBadgeColor(info.activeState, info.result)}>{info.activeState}</Badge>
									<Badge color="dim">{info.subState}</Badge>
									{#if info.result && info.result !== 'success'}
										<Badge color={unitBadgeColor(info.activeState, info.result)}>{info.result}</Badge>
									{/if}
								</div>
							</div>
						{/each}
					</div>

					{#if services.services.length > 0}
						<div class="service-list">
							{#each services.services as service}
								<div class="service-card">
									<div class="service-head">
										<div class="service-title-row">
											<span class="service-name mono">{service.Name}</span>
											<Badge color="accent">{service.Runtime}</Badge>
											<Badge color={unitBadgeColor(service.State, service.Result)}>{service.State}</Badge>
											<Badge color="dim">{service.Status}</Badge>
										</div>
										{#if service.ProjectName}
											<div class="service-project mono">{service.ProjectName}</div>
										{/if}
									</div>

									<div class="service-meta">
										<div class="service-meta-row">
											<span class="detail-label"><Activity size={13} /> Local</span>
											<div class="detail-value">
												{#if service.LocalUrl}
													<a href={service.LocalUrl} target="_blank" class="link">{service.LocalUrl}</a>
												{:else}
													<span class="dim">not exposed</span>
												{/if}
												<Badge color={probeBadgeColor(service.LocalProbe)}>{probeLabel(service.LocalProbe)}</Badge>
											</div>
										</div>
										<div class="service-meta-row">
											<span class="detail-label"><Globe size={13} /> Public</span>
											<div class="detail-value">
												{#if service.PublicUrl}
													<a href={service.PublicUrl} target="_blank" class="link">{service.PublicUrl}</a>
												{:else}
													<span class="dim">none</span>
												{/if}
												<Badge color={probeBadgeColor(service.PublicProbe)}>{probeLabel(service.PublicProbe)}</Badge>
											</div>
										</div>
										<div class="service-meta-row">
											<span class="detail-label">Port</span>
											<div class="detail-value mono">{service.Port ?? '—'}</div>
										</div>
										<div class="service-meta-row">
											<span class="detail-label">Unit</span>
											<div class="detail-value mono">{service.ServiceName || '—'}</div>
										</div>
									</div>

									{#if service.LocalProbe?.preview || service.PublicProbe?.preview}
										<div class="probe-preview">
											{#if service.LocalProbe?.preview}
												<div><span class="probe-preview-label">Local preview</span> {service.LocalProbe.preview}</div>
											{/if}
											{#if service.PublicProbe?.preview}
												<div><span class="probe-preview-label">Public preview</span> {service.PublicProbe.preview}</div>
											{/if}
										</div>
									{/if}

									{#if service.RecentLogs}
										<div class="service-logs">
											<div class="service-logs-label"><FileText size={13} /> Recent logs</div>
											<pre>{service.RecentLogs}</pre>
										</div>
									{/if}
								</div>
							{/each}
						</div>
					{:else}
						<span class="dim">No hosted apps deployed</span>
					{/if}
				{/if}
			</Card>

			<!-- Today's Usage -->
			<Card title="Today's Usage">
				<div class="detail-list">
					{#if tenant.daily_usage}
						<div class="detail-row">
							<span class="detail-label">Runs</span>
							<span class="detail-value mono">
								{tenant.daily_usage.requests}
								{#if tenant.daily_usage.limit_requests}
									<span class="dim"> / {tenant.daily_usage.limit_requests}</span>
								{/if}
							</span>
						</div>
						<div class="detail-row">
							<span class="detail-label">Duration</span>
							<span class="detail-value mono">
								{formatDuration(tenant.daily_usage.duration_ms)}
								{#if tenant.daily_usage.limit_duration_ms}
									<span class="dim"> / {formatDuration(tenant.daily_usage.limit_duration_ms)}</span>
								{/if}
							</span>
						</div>
						{#if tenant.daily_usage.input_tokens > 0}
							<div class="detail-row">
								<span class="detail-label">Tokens (in)</span>
								<span class="detail-value mono">{(tenant.daily_usage.input_tokens / 1000).toFixed(1)}k</span>
							</div>
						{/if}
					{:else}
						<span class="dim">No usage today</span>
					{/if}
				</div>
			</Card>

			<!-- Channels / Groups -->
			<Card title="Channels">
				{#if tenant.groups && tenant.groups.length > 0}
					<div class="groups-list">
						{#each tenant.groups as group}
							<div class="group-row">
								<span class="channel-type {channelType(group.jid)}">{channelType(group.jid)}</span>
								<span class="group-name">{group.name || group.folder}</span>
								<span class="group-folder dim mono">{group.folder}</span>
								{#if group.is_main}<Badge color="accent">main</Badge>{/if}
								{#if !group.requires_trigger}<Badge color="dim">no trigger</Badge>{/if}
							{#if group.hooks_enabled}<Badge color="green">hooks on</Badge>{:else}<Badge color="dim">hooks off</Badge>{/if}
							</div>
							{#if group.hooks_enabled && group.hooks_token}
								<div class="hooks-row">
									<Key size={12} /><span class="mono dim hooks-token" title={group.hooks_token}>{group.hooks_token.slice(0, 16)}&hellip;</span>
									<button class="icon-btn" title="Rotate token" onclick={() => rotateHooksToken(tenant.id, group.jid)}><RotateCcw size={12} /></button>
								</div>
							{/if}
							<div class="hooks-controls">
								{#if group.hooks_enabled}
									<button class="small-btn" onclick={() => toggleHooks(tenant.id, group.jid, false)}>Disable hooks</button>
								{:else}
									<button class="small-btn" onclick={() => toggleHooks(tenant.id, group.jid, true)}>Enable hooks</button>
								{/if}
							</div>
						{/each}
					</div>
				{:else}
					<span class="dim">No channels registered</span>
				{/if}
			</Card>

		</div>

		<Modal
			open={deleteOpen}
			title="Delete Tenant"
			width="460px"
			onclose={() => { deleteOpen = false; deleteConfirmName = ''; }}
		>
			{#snippet children()}
				<div class="delete-dialog">
					<div class="delete-warning">
						<Trash2 size={20} class="delete-icon" />
						<p>This will permanently delete tenant <strong class="mono">{tenant.name}</strong> along with all their data, containers, and Discord resources. This action cannot be undone.</p>
					</div>
					<label class="delete-label" for="delete-confirm">
						Type the tenant name <strong class="mono">{tenant.name}</strong> to confirm:
					</label>
					<input
						id="delete-confirm"
						class="delete-input"
						type="text"
						placeholder={tenant.name}
						bind:value={deleteConfirmName}
						onkeydown={(e) => { if (e.key === 'Enter' && deleteConfirmName === tenant.name) handleDelete(); }}
					/>
				</div>
			{/snippet}
			{#snippet footer()}
				<Button variant="secondary" size="sm" onclick={() => { deleteOpen = false; deleteConfirmName = ''; }}>Cancel</Button>
				<Button
					variant="danger"
					size="sm"
					loading={deleting}
					disabled={deleteConfirmName !== tenant.name}
					onclick={handleDelete}
				>Delete Tenant</Button>
			{/snippet}
		</Modal>

		<TenantModal
			open={editOpen}
			tenant={editingTenant}
			credentials={data.credentials}
			onclose={() => { editOpen = false; editingTenant = null; }}
			onsave={async () => { await fetchTenant(); await data.refetchTenants(); }}
		/>
	{/if}
</div>

<style>
	.page {
		display: flex;
		flex-direction: column;
		gap: 20px;
	}

	.page-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 12px;
		flex-wrap: wrap;
	}
	.page-title {
		font-size: var(--font-size-lg);
		font-weight: 600;
		color: var(--text-bright);
	}
	.page-actions {
		display: flex;
		gap: 8px;
		align-items: center;
	}

	.center {
		display: flex;
		justify-content: center;
		padding: 60px;
		font-size: var(--font-size-sm);
	}
	.dim { color: var(--text-muted); }
	.error { color: var(--rose); }

	.grid {
		display: grid;
		grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
		gap: 16px;
	}

	.detail-list {
		display: flex;
		flex-direction: column;
		gap: 10px;
	}
	.detail-row {
		display: flex;
		align-items: flex-start;
		gap: 8px;
		font-size: var(--font-size-sm);
	}
	.detail-label {
		display: flex;
		align-items: center;
		gap: 4px;
		color: var(--text-dim);
		min-width: 110px;
		flex-shrink: 0;
		padding-top: 1px;
	}
	.detail-value {
		display: flex;
		align-items: center;
		gap: 6px;
		flex-wrap: wrap;
		font-weight: 500;
		color: var(--text);
		word-break: break-all;
	}
	.detail-value.dim { color: var(--text-muted); font-weight: 400; }
	.mono { font-family: var(--font-mono); font-size: var(--font-size-sm); }

	.code-box {
		background: var(--surface-3);
		border: 1px solid var(--border);
		border-radius: var(--radius);
		padding: 2px 10px;
		font-family: var(--font-mono);
		font-size: 15px;
		font-weight: 700;
		letter-spacing: 0.15em;
		color: var(--accent);
	}
	.copy-btn {
		background: none;
		border: none;
		cursor: pointer;
		color: var(--text-muted);
		padding: 2px;
		display: inline-flex;
		align-items: center;
		border-radius: var(--radius);
		transition: color var(--duration);
		text-decoration: none;
	}
	.copy-btn:hover { color: var(--text); }
	.link-row {
		display: flex;
		align-items: center;
		gap: 6px;
		max-width: 100%;
		overflow: hidden;
	}
	.link {
		color: var(--accent);
		text-decoration: none;
		font-family: var(--font-mono);
		font-size: var(--font-size-xs);
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		max-width: 220px;
	}
	.link:hover { text-decoration: underline; }

	.groups-list {
		display: flex;
		flex-direction: column;
		gap: 8px;
	}
	.group-row {
		display: flex;
		align-items: center;
		gap: 8px;
		font-size: var(--font-size-sm);
		flex-wrap: wrap;
	}
	.group-name { font-weight: 500; color: var(--text); }
	.group-folder { font-size: var(--font-size-xs); }
	.hooks-row { display: flex; align-items: center; gap: 6px; font-size: var(--font-size-xs); padding-left: 4px; }
	.hooks-token { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--font-size-xs); }
	.hooks-controls { padding-left: 4px; margin-top: 2px; }
	.small-btn { font-size: var(--font-size-xs); padding: 2px 8px; border: 1px solid var(--border); border-radius: 4px; background: transparent; color: var(--text); cursor: pointer; }
	.small-btn:hover { background: var(--bg-hover); }
	.icon-btn { background: transparent; border: none; cursor: pointer; color: var(--text-muted); padding: 2px; display: inline-flex; align-items: center; }
	.icon-btn:hover { color: var(--text); }

	.channel-type {
		padding: 2px 7px;
		border-radius: 99px;
		font-size: var(--font-size-xs);
		font-weight: 600;
		font-family: var(--font-mono);
	}
	.channel-type.discord { background: rgba(88,101,242,0.15); color: #7289da; }

	.containers-list {
		display: flex;
		flex-direction: column;
		gap: 8px;
	}
	.container-row {
		display: flex;
		align-items: center;
		gap: 8px;
		font-size: var(--font-size-sm);
		flex-wrap: wrap;
	}
	.container-name {
		font-size: var(--font-size-xs);
		color: var(--text);
		word-break: break-all;
	}
	.runtime-summary {
		display: flex;
		flex-direction: column;
		gap: 10px;
		margin-bottom: 14px;
	}
	.runtime-unit {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 10px;
		padding: 10px 12px;
		background: var(--surface-2);
		border: 1px solid var(--border);
		border-radius: var(--radius);
		flex-wrap: wrap;
	}
	.runtime-unit-name {
		color: var(--text);
		font-size: var(--font-size-xs);
	}
	.runtime-unit-badges {
		display: flex;
		gap: 6px;
		flex-wrap: wrap;
	}
	.service-list {
		display: flex;
		flex-direction: column;
		gap: 12px;
	}
	.service-card {
		display: flex;
		flex-direction: column;
		gap: 12px;
		padding: 12px;
		background: var(--surface-2);
		border: 1px solid var(--border);
		border-radius: var(--radius);
	}
	.service-head {
		display: flex;
		flex-direction: column;
		gap: 6px;
	}
	.service-title-row {
		display: flex;
		align-items: center;
		gap: 8px;
		flex-wrap: wrap;
	}
	.service-name {
		color: var(--text-bright);
		font-size: var(--font-size-sm);
		font-weight: 700;
	}
	.service-project {
		color: var(--text-muted);
		font-size: var(--font-size-xs);
	}
	.service-meta {
		display: flex;
		flex-direction: column;
		gap: 8px;
	}
	.service-meta-row {
		display: flex;
		align-items: flex-start;
		gap: 8px;
		font-size: var(--font-size-sm);
	}
	.probe-preview {
		display: flex;
		flex-direction: column;
		gap: 4px;
		font-size: var(--font-size-xs);
		color: var(--text-muted);
	}
	.probe-preview-label {
		color: var(--text-dim);
		font-weight: 600;
	}
	.service-logs {
		display: flex;
		flex-direction: column;
		gap: 6px;
	}
	.service-logs-label {
		display: flex;
		align-items: center;
		gap: 6px;
		font-size: var(--font-size-xs);
		color: var(--text-dim);
	}
	.service-logs pre {
		margin: 0;
		padding: 10px 12px;
		background: #0e1520;
		border: 1px solid var(--border);
		border-radius: var(--radius);
		color: #cfe1ff;
		font-family: var(--font-mono);
		font-size: 12px;
		line-height: 1.45;
		white-space: pre-wrap;
		word-break: break-word;
		max-height: 220px;
		overflow: auto;
	}
	.channel-type.telegram { background: rgba(0,136,204,0.12); color: #0088cc; }

	.disk-breakdown {
		display: flex;
		flex-direction: column;
		gap: 4px;
		width: 100%;
	}
	.disk-item {
		display: flex;
		align-items: center;
		justify-content: space-between;
		gap: 8px;
		padding: 4px 8px;
		background: var(--surface-2);
		border: 1px solid var(--border);
		border-radius: var(--radius);
		font-size: var(--font-size-xs);
	}
	.disk-item-volume {
		margin-left: 12px;
		opacity: 0.85;
	}
	.disk-label {
		color: var(--text-dim);
		font-family: var(--font-mono);
	}
	.disk-val {
		color: var(--text);
		font-weight: 600;
	}
	.channel-type.whatsapp { background: rgba(37,211,102,0.12); color: #25d366; }
	.channel-type.slack { background: rgba(74,21,75,0.15); color: #e01e5a; }

	.delete-dialog {
		display: flex;
		flex-direction: column;
		gap: 16px;
	}
	.delete-warning {
		display: flex;
		gap: 12px;
		align-items: flex-start;
		padding: 14px;
		background: rgba(251, 113, 133, 0.08);
		border: 1px solid rgba(251, 113, 133, 0.25);
		border-radius: var(--radius);
		color: var(--text);
		font-size: var(--font-size-sm);
		line-height: 1.5;
	}
	:global(.delete-icon) {
		color: var(--rose);
		flex-shrink: 0;
		margin-top: 1px;
	}
	.delete-label {
		font-size: var(--font-size-sm);
		color: var(--text-dim);
	}
	.delete-input {
		width: 100%;
		padding: 8px 12px;
		background: var(--surface-2);
		border: 1px solid var(--border);
		border-radius: var(--radius);
		color: var(--text);
		font-family: var(--font-mono);
		font-size: var(--font-size-sm);
		box-sizing: border-box;
		outline: none;
	}
	.delete-input:focus {
		border-color: var(--rose);
	}
</style>
