<script lang="ts">
	import Modal from '$lib/components/common/modal/Modal.svelte'
	import { Button, Alert } from '$lib/components/common'
	import { Loader2, CheckCircle2, XCircle, Terminal, ChevronDown, ChevronUp } from 'lucide-svelte'
	import GitDiffPreview from '../GitDiffPreview.svelte'
	import { JobService } from '$lib/gen'
	import { workspaceStore } from '$lib/stores'
	import hubPaths from '$lib/hubPaths.json'
	import { jobManager } from '$lib/services/JobManager'
	import type { SyncResponse, SettingsObject } from '$lib/git-sync'

	interface Props {
		open: boolean
		gitRepoResourcePath: string
		uiState: SettingsObject
		onSuccess?: () => void
		isNewConnection?: boolean
		onSaveWithoutInit?: () => void
	}

	let {
		open = $bindable(false),
		gitRepoResourcePath,
		uiState,
		onSuccess,
		isNewConnection = false,
		onSaveWithoutInit
	}: Props = $props()

	// Job state
	let previewJobId = $state<string | null>(null)
	let previewJobStatus = $state<'running' | 'success' | 'failure' | undefined>(undefined)
	let isPreviewLoading = $state(false)
	let previewError = $state('')

	let applyJobId = $state<string | null>(null)
	let applyJobStatus = $state<'running' | 'success' | 'failure' | undefined>(undefined)
	let isApplying = $state(false)
	let applyError = $state('')

	// UI state
	let showCliInstructions = $state(false)
	let previewResult = $state<SyncResponse | null>(null)

	// Note: Escape key is handled by the Modal component itself

	// Reset state when modal opens/closes
	$effect(() => {
		if (!open) {
			previewJobId = null
			previewJobStatus = undefined
			isPreviewLoading = false
			previewError = ''
			applyJobId = null
			applyJobStatus = undefined
			isApplying = false
			applyError = ''
			showCliInstructions = false
			previewResult = null
		}
	})

	// Execute job with dry run or actual execution
	async function executeJob(isDryRun: boolean) {
		const isPreview = isDryRun

		if (isPreview) {
			isPreviewLoading = true
			previewError = ''
			previewResult = null
			previewJobId = null
			previewJobStatus = undefined
		} else {
			isApplying = true
			applyError = ''
			applyJobId = null
			applyJobStatus = undefined
		}

		try {
			const workspace = $workspaceStore
			if (!workspace) return

			const payload = {
				workspace_id: workspace,
				repo_url_resource_path: gitRepoResourcePath,
				dry_run: isDryRun,
				pull: false,
				settings_json: JSON.stringify(uiState)
			}

			const jobId = await JobService.runScriptByPath({
				workspace,
				path: hubPaths.gitInitRepo,
				requestBody: payload,
				skipPreprocessor: true
			})

			if (isPreview) {
				previewJobId = jobId
				previewJobStatus = 'running'
			} else {
				applyJobId = jobId
				applyJobStatus = 'running'
			}

			// Use JobManager instead of tryEvery
			const result = await jobManager.runWithProgress(() => Promise.resolve(jobId), {
				workspace,
				timeout: 60000,
				timeoutMessage: `${isPreview ? 'Preview' : 'Apply'} job timed out after 60s`,
				onProgress: (status) => {
					if (isPreview) {
						previewJobStatus = status.status
					} else {
						applyJobStatus = status.status
					}

					// Handle failure status
					if (status.status === 'failure') {
						if (isPreview) {
							previewError = status.error || 'Preview failed'
						} else {
							applyError = status.error || 'Push failed'
						}
					}
				}
			})

			// Handle successful result
			if (isPreview) {
				if (previewJobStatus === 'success') {
					previewResult = result as SyncResponse
				}
			} else {
				if (applyJobStatus === 'success') {
					onSuccess?.()
				}
			}
		} catch (e) {
			const errorMsg = e?.message || 'Operation failed'
			if (isPreview) {
				previewJobStatus = 'failure'
				previewError = errorMsg
			} else {
				applyJobStatus = 'failure'
				applyError = errorMsg
			}
		} finally {
			if (isPreview) {
				isPreviewLoading = false
			} else {
				isApplying = false
			}
		}
	}
</script>

<Modal bind:open title="Push Workspace to Git Repository" class="sm:max-w-4xl">
	<div class="flex flex-col gap-4">
		<!-- Description -->
		<p class="text-sm text-secondary"
			>Push your current workspace content to the connected Git repository based on the configured
			filters.</p
		>
		<p class="text-sm text-primary"
			>Note: This will not update git sync settings in wmill.yaml. Settings can only be pulled from
			the repository as it is the source of truth.</p
		>

		<!-- Settings display for new connections -->
		{#if isNewConnection}
			<div class="bg-surface-secondary border border-border rounded-lg p-3">
				<h4 class="text-sm font-medium text-primary mb-2"
					>Settings that will be pushed to repository</h4
				>
				<div class="text-xs text-secondary space-y-1">
					<div><strong>Include paths:</strong> {uiState.include_path?.join(', ') || 'None'}</div>
					<div><strong>Exclude paths:</strong> {uiState.exclude_path?.join(', ') || 'None'}</div>
					{#if uiState.extra_include_path?.length > 0}
						<div><strong>Extra include paths:</strong> {uiState.extra_include_path.join(', ')}</div>
					{/if}
					<div><strong>Include types:</strong> {uiState.include_type?.join(', ') || 'None'}</div>
				</div>
				<p class="text-xs text-primary mt-2"
					>To modify these settings, cancel and configure them in the workspace settings.</p
				>
			</div>
		{/if}

		<!-- Preview section -->
		{#if !previewResult}
			<div class="flex justify-start pt-4">
				<Button
					size="md"
					variant="accent"
					onclick={() => executeJob(true)}
					disabled={isPreviewLoading}
					startIcon={{
						icon: isPreviewLoading ? Loader2 : undefined,
						classes: isPreviewLoading ? 'animate-spin' : ''
					}}
				>
					{isPreviewLoading ? 'Previewing...' : 'Preview changes'}
				</Button>
			</div>
		{/if}

		<!-- Job status for preview -->
		{#if previewJobId}
			<div class="flex items-center gap-2 text-xs text-primary">
				{#if previewJobStatus === 'running'}
					<Loader2 class="animate-spin" size={14} />
				{:else if previewJobStatus === 'success'}
					<CheckCircle2 size={14} class="text-green-600" />
				{:else if previewJobStatus === 'failure'}
					<XCircle size={14} class="text-red-700" />
				{/if}
				Preview job:
				<a
					target="_blank"
					class="underline"
					href={`/run/${previewJobId}?workspace=${$workspaceStore}`}
				>
					{previewJobId}
				</a>
			</div>
		{/if}

		<!-- Preview error -->
		{#if previewError}
			<Alert type="error" title="Preview failed">
				{previewError}
			</Alert>
		{/if}

		<!-- Preview results -->
		{#if previewResult && !previewError}
			<div class="space-y-3">
				<h4 class="text-sm font-semibold text-primary">Changes to Push</h4>

				{#if previewResult.changes?.length > 0}
					<GitDiffPreview {previewResult} />
				{:else}
					<div class="bg-surface-secondary rounded-lg p-3">
						<div class="text-sm text-primary">No changes to push to the repository.</div>
					</div>
				{/if}
			</div>
		{/if}

		<!-- Apply section (shown after successful preview) -->
		{#if previewResult && !previewError}
			{@const hasChanges = previewResult.changes?.length > 0}
			{#if hasChanges}
				<div class="border-t pt-4 mt-4">
					<div class="flex justify-start gap-2">
						<Button
							size="xs"
							onclick={() => executeJob(false)}
							disabled={isApplying}
							startIcon={{
								icon: isApplying ? Loader2 : undefined,
								classes: isApplying ? 'animate-spin' : ''
							}}
						>
							{isApplying
								? isNewConnection
									? 'Initializing...'
									: 'Pushing...'
								: isNewConnection
									? 'Initialize repo and save connection'
									: 'Push to repository'}
						</Button>
						{#if isNewConnection && onSaveWithoutInit}
							<Button size="xs" color="light" onclick={onSaveWithoutInit} disabled={isApplying}>
								Save without initializing repo
							</Button>
						{/if}
					</div>
				</div>
			{/if}
		{/if}

		<!-- Job status for apply -->
		{#if applyJobId}
			<div class="flex items-center gap-2 text-xs text-primary">
				{#if applyJobStatus === 'running'}
					<Loader2 class="animate-spin" size={14} />
				{:else if applyJobStatus === 'success'}
					<CheckCircle2 size={14} class="text-green-600" />
				{:else if applyJobStatus === 'failure'}
					<XCircle size={14} class="text-red-700" />
				{/if}
				Push job:
				<a
					target="_blank"
					class="underline"
					href={`/run/${applyJobId}?workspace=${$workspaceStore}`}
				>
					{applyJobId}
				</a>
			</div>
		{/if}

		<!-- Apply error -->
		{#if applyError}
			<Alert type="error" title="Push failed">
				{applyError}
			</Alert>
		{/if}

		<!-- CLI Instructions (collapsible) -->
		<div class="border-t pt-4 mt-4">
			<button
				class="flex items-center gap-2 text-sm text-secondary hover:text-primary transition-colors"
				onclick={() => (showCliInstructions = !showCliInstructions)}
			>
				<Terminal size={16} />
				<span>CLI Instructions</span>
				{#if showCliInstructions}
					<ChevronUp size={16} />
				{:else}
					<ChevronDown size={16} />
				{/if}
			</button>

			{#if showCliInstructions}
				<div class="mt-3 bg-surface-secondary rounded-lg p-3">
					<pre class="text-xs bg-surface p-3 rounded overflow-x-auto whitespace-pre-wrap break-all">
# Setup (only needed if local folder not initialized yet)
npm install -g windmill-cli
wmill workspace add {$workspaceStore} {$workspaceStore} {window.location.origin}
wmill init --workspace {$workspaceStore} --repository {gitRepoResourcePath}

# Pull workspace content to git repository
wmill sync pull --workspace {$workspaceStore} --repository {gitRepoResourcePath}</pre
					>
				</div>
			{/if}
		</div>
	</div>
</Modal>
