<script lang="ts">
	import { page } from '$app/stores';
	import type { Project, Stage, Instance, Deploy } from '$lib/types';
	import * as api from '$lib/api';
	import StatusBadge from '$lib/components/StatusBadge.svelte';
	import InstanceCard from '$lib/components/InstanceCard.svelte';
	import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
	import EmptyState from '$lib/components/EmptyState.svelte';
	import Skeleton from '$lib/components/Skeleton.svelte';
	import { IconTrash, IconKey, IconHardDrive, IconDeploy, IconClock, IconLoader, IconPlus, IconEdit, IconCheck, IconX } from '$lib/components/icons';
	import Breadcrumb from '$lib/components/Breadcrumb.svelte';
	import FormField from '$lib/components/FormField.svelte';
	import ToggleSwitch from '$lib/components/ToggleSwitch.svelte';
	import { toasts } from '$lib/stores/toast';
	import { t } from '$lib/i18n';

	let project = $state<Project | null>(null);
	let stages = $state<Stage[]>([]);
	let instancesByStage = $state<Record<string, Instance[]>>({});
	let deploys = $state<Deploy[]>([]);
	let loading = $state(true);
	let error = $state('');

	let deployStageId = $state('');
	let deployTag = $state('');
	let deployLoading = $state(false);
	let deployError = $state('');

	let availableTags = $state<string[]>([]);

	// Add stage form
	let showAddStage = $state(false);
	let stageName = $state('');
	let stageTagPattern = $state('*');
	let stageAutoDeploy = $state(true);
	let stageEnableProxy = $state(true);
	let stageMaxInstances = $state('1');
	let stageCpuLimit = $state('');
	let stageMemoryLimit = $state('');
	let addingStage = $state(false);

	async function handleAddStage() {
		if (!stageName.trim()) return;
		addingStage = true;
		try {
			await api.createStage(projectId, {
				name: stageName.trim(),
				tag_pattern: stageTagPattern.trim() || '*',
				auto_deploy: stageAutoDeploy,
				enable_proxy: stageEnableProxy,
				max_instances: parseInt(stageMaxInstances) || 1,
				cpu_limit: parseFloat(stageCpuLimit) || 0,
				memory_limit: parseInt(stageMemoryLimit) || 0,
			});
			toasts.success($t('projectDetail.stageCreated', { name: stageName }));
			stageName = ''; stageTagPattern = '*'; stageAutoDeploy = true; stageEnableProxy = true; stageMaxInstances = '1'; stageCpuLimit = ''; stageMemoryLimit = '';
			showAddStage = false;
			await loadProject();
		} catch (e) {
			toasts.error(e instanceof Error ? e.message : $t('projectDetail.stageCreateFailed'));
		} finally {
			addingStage = false;
		}
	}

	// Edit project
	let editing = $state(false);
	let editName = $state('');
	let editImage = $state('');
	let editPort = $state('');
	let editHealthcheck = $state('');
	let editAccessListId = $state('');
	let saving = $state(false);

	function startEditing() {
		if (!project) return;
		editName = project.name;
		editImage = project.image;
		editPort = String(project.port || '');
		editHealthcheck = project.healthcheck || '';
		editAccessListId = String(project.npm_access_list_id || '0');
		editing = true;
	}

	async function saveProject() {
		if (!editName.trim() || !editImage.trim()) return;
		saving = true;
		try {
			await api.updateProject(projectId, {
				name: editName.trim(),
				image: editImage.trim(),
				port: parseInt(editPort) || 0,
				healthcheck: editHealthcheck.trim(),
				npm_access_list_id: parseInt(editAccessListId) || 0,
			});
			toasts.success($t('projectDetail.projectUpdated'));
			editing = false;
			await loadProject();
		} catch (e) {
			toasts.error(e instanceof Error ? e.message : $t('projectDetail.updateFailed'));
		} finally {
			saving = false;
		}
	}

	async function handleDeleteStage(stageId: string, name: string) {
		try {
			await api.deleteStage(projectId, stageId);
			toasts.success($t('projectDetail.stageDeleted', { name }));
			await loadProject();
		} catch (e) {
			toasts.error(e instanceof Error ? e.message : $t('projectDetail.stageDeleteFailed'));
		}
	}
	let tagsLoading = $state(false);
	let settingsDomain = $state('');

	let showDeleteConfirm = $state(false);

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

	async function loadProject() {
		if (!project) loading = true;
		error = '';
		try {
			const detail = await api.getProject(projectId);
			project = detail.project;
			stages = detail.stages ?? [];

			const instanceResults = await Promise.all(
				stages.map(async (s) => {
					try {
						const instances = await api.listInstances(projectId, s.id);
						return { stageId: s.id, instances };
					} catch {
						return { stageId: s.id, instances: [] };
					}
				})
			);

			const mapped: Record<string, Instance[]> = {};
			for (const r of instanceResults) {
				mapped[r.stageId] = r.instances;
			}
			instancesByStage = mapped;

			try {
				const allDeploys = await api.listDeploys(20);
				deploys = allDeploys.filter((d) => d.project_id === projectId);
			} catch {
				deploys = [];
			}

			try {
				const settings = await api.getSettings();
				settingsDomain = settings.domain ?? '';
			} catch { /* non-critical */ }
		} catch (e) {
			error = e instanceof Error ? e.message : $t('projectDetail.loadFailed');
		} finally {
			loading = false;
		}
	}

	async function loadTags(stageId: string) {
		deployStageId = stageId;
		deployTag = '';
		availableTags = [];

		if (!project?.registry || !project?.image) return;

		tagsLoading = true;
		try {
			// Look up registry ID from name.
			const registries = await api.listRegistries();
			const reg = registries.find(r => r.name === project?.registry);
			if (reg) {
				availableTags = await api.listRegistryTags(reg.id, project.image);
			}
		} catch {
			availableTags = [];
		} finally {
			tagsLoading = false;
		}
	}

	async function handleDeploy() {
		if (!deployTag.trim() || !deployStageId) return;

		deployLoading = true;
		deployError = '';
		try {
			await api.deployInstance(projectId, deployStageId, deployTag.trim());
			deployTag = '';
			deployStageId = '';
			await loadProject();
		} catch (e) {
			deployError = e instanceof Error ? e.message : $t('projectDetail.deployFailed');
		} finally {
			deployLoading = false;
		}
	}

	async function handleDeleteProject() {
		showDeleteConfirm = false;
		try {
			await api.deleteProject(projectId);
			window.location.href = '/projects';
		} catch (e) {
			error = e instanceof Error ? e.message : $t('projectDetail.deleteFailed');
		}
	}

	$effect(() => {
		void projectId;
		loadProject();
	});
</script>

<svelte:head>
	<title>{project?.name ?? $t('common.project')} - {$t('app.name')}</title>
</svelte:head>

{#if loading}
	<div class="space-y-6">
		<div class="flex items-start justify-between">
			<div class="space-y-2">
				<Skeleton width="4rem" height="0.875rem" />
				<Skeleton width="12rem" height="1.75rem" />
				<Skeleton width="16rem" height="0.875rem" />
			</div>
		</div>
		<div class="grid grid-cols-4 gap-4">
			{#each Array(4) as _}
				<Skeleton height="3rem" />
			{/each}
		</div>
	</div>
{:else if error}
	<div class="rounded-xl border border-[var(--color-danger-light)] bg-[var(--color-danger-light)] p-4">
		<p class="text-sm text-[var(--color-danger)]">{error}</p>
		<button type="button" class="mt-2 text-sm font-medium text-[var(--color-danger)] underline hover:no-underline" onclick={loadProject}>
			{$t('common.retry')}
		</button>
	</div>
{:else if project}
	<div class="space-y-6">
		<!-- Header -->
		<div class="flex items-start justify-between">
			<div>
				<Breadcrumb items={[{ label: $t('projects.title'), href: '/projects' }]} />
				<h1 class="mt-1 text-2xl font-bold text-[var(--text-primary)]">{project.name}</h1>
				<p class="mt-1 font-mono text-sm text-[var(--text-tertiary)]">{project.image}</p>
			</div>
			<button
				type="button"
				class="inline-flex items-center gap-2 rounded-lg border border-[var(--color-danger)] px-3 py-2 text-sm font-medium text-[var(--color-danger)] hover:bg-[var(--color-danger-light)] transition-colors active:animate-press"
				onclick={() => { showDeleteConfirm = true; }}
			>
				<IconTrash size={16} />
				{$t('projectDetail.deleteProject')}
			</button>
		</div>

		<!-- Project settings links -->
		<div class="flex gap-3">
			<a
				href="/projects/{projectId}/env"
				class="inline-flex items-center gap-2 rounded-lg border border-[var(--border-primary)] bg-[var(--surface-card)] px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] transition-colors"
			>
				<IconKey size={16} />
				{$t('projectDetail.envVars')}
			</a>
			<a
				href="/projects/{projectId}/volumes"
				class="inline-flex items-center gap-2 rounded-lg border border-[var(--border-primary)] bg-[var(--surface-card)] px-4 py-2 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] transition-colors"
			>
				<IconHardDrive size={16} />
				{$t('projectDetail.volumes')}
			</a>
		</div>

		<!-- Project info -->
		<div class="rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-5 shadow-[var(--shadow-sm)]">
			{#if editing}
				<div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
					<FormField label={$t('projectDetail.nameLabel')} name="editName" bind:value={editName} />
					<FormField label={$t('projectDetail.imageLabel')} name="editImage" bind:value={editImage} />
					<FormField label={$t('projectDetail.portLabel')} name="editPort" type="number" bind:value={editPort} />
					<FormField label={$t('projectDetail.healthcheckLabel')} name="editHealthcheck" bind:value={editHealthcheck} placeholder="/api/health" />
					<FormField label={$t('projectDetail.accessListId')} name="editAccessListId" type="number" bind:value={editAccessListId} placeholder="0" helpText={$t('projectDetail.accessListIdHelp')} />
				</div>
				<div class="mt-4 flex items-center gap-2 justify-end">
					<button
						type="button"
						onclick={() => { editing = false; }}
						class="inline-flex items-center gap-1.5 rounded-lg border border-[var(--border-primary)] px-3 py-1.5 text-sm font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] transition-colors"
					>
						<IconX size={14} />
						{$t('projects.cancel')}
					</button>
					<button
						type="button"
						onclick={saveProject}
						disabled={saving || !editName.trim() || !editImage.trim()}
						class="inline-flex items-center gap-1.5 rounded-lg bg-[var(--color-brand-600)] px-3 py-1.5 text-sm font-medium text-white hover:bg-[var(--color-brand-700)] disabled:opacity-50 transition-colors"
					>
						<IconCheck size={14} />
						{saving ? $t('projectDetail.saving') : $t('common.save')}
					</button>
				</div>
			{:else}
				<div class="flex items-start justify-between">
					<div class="grid grid-cols-2 gap-4 flex-1 sm:grid-cols-4">
						<div>
							<p class="text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('projects.port')}</p>
							<p class="mt-1 text-sm text-[var(--text-primary)]">{project.port || 'Auto'}</p>
						</div>
						<div>
							<p class="text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('projects.healthcheck')}</p>
							<p class="mt-1 text-sm text-[var(--text-primary)]">{project.healthcheck || 'Auto'}</p>
						</div>
						<div>
							<p class="text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('projects.registry')}</p>
							<p class="mt-1 text-sm text-[var(--text-primary)]">{project.registry || '-'}</p>
						</div>
						<div>
							<p class="text-xs font-medium text-[var(--text-tertiary)] uppercase">{$t('projects.created')}</p>
							<p class="mt-1 text-sm text-[var(--text-primary)]">{new Date(project.created_at).toLocaleDateString()}</p>
						</div>
					</div>
					<button
						type="button"
						onclick={startEditing}
						title={$t('common.edit')}
						class="rounded-lg p-2 text-[var(--text-tertiary)] hover:bg-[var(--surface-card-hover)] hover:text-[var(--text-link)] transition-colors"
					>
						<IconEdit size={16} />
					</button>
				</div>
			{/if}
		</div>

		<!-- Stages & Instances -->
		<div>
			<div class="flex items-center justify-between">
				<h2 class="text-lg font-semibold text-[var(--text-primary)]">{$t('projectDetail.stages')}</h2>
				<button
					type="button"
					onclick={() => { showAddStage = !showAddStage; }}
					class="inline-flex items-center gap-1.5 rounded-lg {showAddStage ? 'border border-[var(--border-primary)] text-[var(--text-secondary)]' : 'bg-[var(--color-brand-600)] text-white'} px-3 py-1.5 text-xs font-medium transition-all hover:opacity-90"
				>
					{#if !showAddStage}<IconPlus size={14} />{/if}
					{showAddStage ? $t('projects.cancel') : $t('projectDetail.addStage')}
				</button>
			</div>

			{#if showAddStage}
				<div class="mt-3 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-4 animate-scale-in">
					<div class="grid grid-cols-2 gap-3 sm:grid-cols-4">
						<FormField label={$t('projectDetail.nameLabel')} name="stageName" bind:value={stageName} placeholder="dev" />
						<FormField label={$t('projectDetail.tagPattern')} name="stagePattern" bind:value={stageTagPattern} placeholder="dev-*" helpText={$t('projectDetail.tagPatternHelp')} />
						<FormField label={$t('projectDetail.maxInstances')} name="stageMax" type="number" bind:value={stageMaxInstances} />
						<div class="flex gap-4 items-end">
							<div class="flex flex-col gap-1.5">
								<label class="text-sm font-medium text-[var(--text-primary)]">{$t('projectDetail.autoDeployLabel')}</label>
								<div class="flex items-center h-[38px]">
									<ToggleSwitch bind:checked={stageAutoDeploy} label={$t('projectDetail.autoDeployLabel')} />
								</div>
							</div>
							<div class="flex flex-col gap-1.5">
								<label class="text-sm font-medium text-[var(--text-primary)]">{$t('projectDetail.enableProxy')}</label>
								<div class="flex items-center h-[38px]">
									<ToggleSwitch bind:checked={stageEnableProxy} label={$t('projectDetail.enableProxy')} />
								</div>
							</div>
						</div>
					</div>
					<div class="mt-3 grid grid-cols-2 gap-3 sm:grid-cols-4">
						<FormField label={$t('projectDetail.cpuLimit')} name="stageCpu" type="number" bind:value={stageCpuLimit} placeholder="0" helpText={$t('projectDetail.cpuLimitHelp')} />
						<FormField label={$t('projectDetail.memoryLimit')} name="stageMem" type="number" bind:value={stageMemoryLimit} placeholder="0" helpText={$t('projectDetail.memoryLimitHelp')} />
					</div>
					<div class="mt-3 flex justify-end">
						<button
							type="button"
							onclick={handleAddStage}
							disabled={addingStage || !stageName.trim()}
							class="rounded-lg bg-[var(--color-brand-600)] px-4 py-2 text-sm font-medium text-white hover:bg-[var(--color-brand-700)] disabled:opacity-50 transition-all"
						>
							{addingStage ? $t('projectDetail.creating') : $t('projectDetail.createStage')}
						</button>
					</div>
				</div>
			{/if}

			{#if stages.length === 0 && !showAddStage}
				<div class="mt-4">
					<EmptyState title={$t('projectDetail.noStages')} icon="instances" />
				</div>
			{:else}
				<div class="mt-4 space-y-4">
					{#each stages as stage (stage.id)}
						{@const stageInstances = instancesByStage[stage.id] ?? []}
						<div class="rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] shadow-[var(--shadow-sm)] overflow-hidden">
							<!-- Stage header -->
							<div class="flex items-center justify-between flex-wrap gap-2 border-b border-[var(--border-secondary)] px-5 py-4">
								<div class="flex items-center gap-3 flex-wrap">
									<h3 class="text-base font-semibold text-[var(--text-primary)]">{stage.name}</h3>
									<span class="rounded-md bg-[var(--surface-card-hover)] px-2 py-0.5 font-mono text-xs text-[var(--text-tertiary)]">{stage.tag_pattern}</span>
									{#if stage.auto_deploy}
										<span class="rounded-full badge-success rounded-full px-2 py-0.5 text-xs font-medium">{$t('projectDetail.autoDeploy')}</span>
									{/if}
									{#if stage.confirm}
										<span class="rounded-full badge-warning rounded-full px-2 py-0.5 text-xs font-medium">{$t('projectDetail.requiresConfirm')}</span>
									{/if}
									{#if !stage.enable_proxy}
										<span class="rounded-full badge-gray rounded-full px-2 py-0.5 text-xs font-medium">{$t('projectDetail.noProxy')}</span>
									{/if}
								</div>
								<div class="flex items-center gap-3">
									<span class="text-xs text-[var(--text-tertiary)]">
										{stageInstances.length} / {stage.max_instances} {$t('projectDetail.instances')}
									</span>
									<button
										type="button"
										class="inline-flex items-center gap-1.5 rounded-lg bg-[var(--color-brand-600)] px-3 py-1.5 text-xs font-medium text-white hover:bg-[var(--color-brand-700)] transition-colors active:animate-press"
										onclick={() => loadTags(stage.id)}
									>
										<IconDeploy size={14} />
										{$t('projectDetail.deployNewVersion')}
									</button>
									<button
										type="button"
										title={$t('projectDetail.deleteStage')}
										onclick={() => { if (confirm($t('projectDetail.deleteStageConfirm', { name: stage.name }))) handleDeleteStage(stage.id, stage.name); }}
										class="rounded-lg p-1.5 text-[var(--text-tertiary)] hover:bg-[var(--color-danger-light)] hover:text-[var(--color-danger)] transition-colors"
									>
										<IconTrash size={14} />
									</button>
								</div>
							</div>

							<!-- Deploy form -->
							{#if deployStageId === stage.id}
								<div class="border-b border-[var(--border-secondary)] bg-[var(--surface-card-hover)] px-5 py-4 animate-scale-in">
									<div class="flex items-end gap-3">
										<div class="flex-1">
											<label for="deploy-tag-{stage.id}" class="block text-xs font-medium text-[var(--text-secondary)]">
												{$t('projectDetail.selectTag')}
											</label>
											{#if tagsLoading}
												<div class="mt-1 flex items-center gap-2 text-sm text-[var(--text-tertiary)]">
													<IconLoader size={16} />
													{$t('projectDetail.loadingTags')}
												</div>
											{:else if availableTags.length > 0}
												<select
													id="deploy-tag-{stage.id}"
													bind:value={deployTag}
													class="mt-1 block w-full rounded-lg border border-[var(--border-input)] bg-[var(--surface-input)] px-3 py-2 text-sm text-[var(--text-primary)] focus:border-[var(--color-brand-500)] focus:ring-2 focus:ring-[var(--color-brand-500)] focus:outline-none"
												>
													<option value="">{$t('projectDetail.chooseTag')}</option>
													{#each availableTags as tag}
														<option value={tag}>{tag}</option>
													{/each}
												</select>
											{:else}
												<input
													id="deploy-tag-{stage.id}"
													type="text"
													bind:value={deployTag}
													placeholder={$t('projectDetail.enterTag')}
													class="mt-1 block w-full rounded-lg border border-[var(--border-input)] bg-[var(--surface-input)] px-3 py-2 text-sm text-[var(--text-primary)] focus:border-[var(--color-brand-500)] focus:ring-2 focus:ring-[var(--color-brand-500)] focus:outline-none"
												/>
											{/if}
										</div>
										<button
											type="button"
											class="rounded-lg bg-[var(--color-brand-600)] px-4 py-2 text-sm font-medium text-white hover:bg-[var(--color-brand-700)] disabled:opacity-50 transition-colors active:animate-press"
											disabled={!deployTag.trim() || deployLoading}
											onclick={handleDeploy}
										>
											{deployLoading ? $t('projectDetail.deploying') : $t('projectDetail.deploy')}
										</button>
										<button
											type="button"
											class="rounded-lg px-3 py-2 text-sm text-[var(--text-secondary)] hover:bg-[var(--surface-card)] transition-colors"
											onclick={() => { deployStageId = ''; }}
										>
											{$t('common.cancel')}
										</button>
									</div>
									{#if deployError}
										<p class="mt-2 text-xs text-[var(--color-danger)]">{deployError}</p>
									{/if}
								</div>
							{/if}

							<!-- Instances -->
							<div class="p-5">
								{#if stageInstances.length === 0}
									<p class="text-center text-sm text-[var(--text-tertiary)]">{$t('projectDetail.noInstancesRunning')}</p>
								{:else}
									<div class="space-y-3">
										{#each stageInstances as instance (instance.id)}
											<InstanceCard
												{instance}
												{projectId}
												domain={settingsDomain}
												onchange={loadProject}
											/>
										{/each}
									</div>
								{/if}
							</div>
						</div>
					{/each}
				</div>
			{/if}
		</div>

		<!-- Deploy History Timeline -->
		<div>
			<h2 class="text-lg font-semibold text-[var(--text-primary)]">{$t('projectDetail.recentDeploys')}</h2>

			{#if deploys.length === 0}
				<p class="mt-4 text-sm text-[var(--text-tertiary)]">{$t('projectDetail.noDeployHistory')}</p>
			{:else}
				<div class="mt-4 space-y-3">
					{#each deploys as deploy (deploy.id)}
						<div class="flex items-start gap-4 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-4 shadow-[var(--shadow-sm)]">
							<!-- Timeline dot -->
							<div class="mt-1 flex flex-col items-center">
								<div class="h-3 w-3 rounded-full {deploy.status === 'success' ? 'bg-emerald-500' : deploy.status === 'failed' ? 'bg-red-500' : 'bg-blue-500'}"></div>
							</div>
							<!-- Content -->
							<div class="flex-1 min-w-0">
								<div class="flex items-center gap-2 flex-wrap">
									<span class="font-mono text-sm font-medium text-[var(--text-primary)]">{deploy.image_tag}</span>
									<StatusBadge status={deploy.status} size="sm" />
								</div>
								<div class="mt-1 flex items-center gap-4 text-xs text-[var(--text-tertiary)]">
									{#if deploy.started_at}
										<span class="inline-flex items-center gap-1">
											<IconClock size={12} />
											{new Date(deploy.started_at).toLocaleString()}
										</span>
									{/if}
									{#if deploy.finished_at}
										<span>→ {new Date(deploy.finished_at).toLocaleString()}</span>
									{/if}
								</div>
								{#if deploy.error}
									<p class="mt-1 text-xs text-[var(--color-danger)] truncate">{deploy.error}</p>
								{/if}
							</div>
						</div>
					{/each}
				</div>
			{/if}
		</div>
	</div>

	<ConfirmDialog
		open={showDeleteConfirm}
		title={$t('projectDetail.deleteConfirmTitle')}
		message={$t('projectDetail.deleteConfirmMessage', { name: project.name })}
		confirmLabel={$t('common.delete')}
		confirmVariant="danger"
		onconfirm={handleDeleteProject}
		oncancel={() => { showDeleteConfirm = false; }}
	/>
{/if}
