<!-- #region BulkReplaceModal [C:3] [TYPE Component] [SEMANTICS translate, bulk, replace, find-replace, regex] -->
<!-- @BRIEF Modal dialog for bulk find-and-replace on translated values within a completed run. -->
<!-- @LAYER UI -->
<!-- @RELATION DEPENDS_ON -> [TranslateApi] -->
<!--
@UX_STATE closed -> Modal closed, no interaction
@UX_STATE configuring -> User entering find/replace pattern, toggling regex, selecting language
@UX_STATE previewing -> Preview table showing affected rows before/after
@UX_STATE preview_error -> Failed to load preview
@UX_STATE confirming -> "Apply X changes?" confirmation dialog
@UX_STATE applying -> API apply in progress
@UX_STATE applied -> Success state with count
@UX_STATE apply_error -> Apply failed with error message
-->
<script lang="ts">
	import { addToast } from '$lib/toasts.svelte.js';
	import { bulkFindReplace, bulkReplacePreview } from '$lib/api/translate.js';
	import { t, _ } from '$lib/i18n/index.svelte.js';

	/** @type {{ show: boolean, runId: string, targetLanguages: string[], onClose: () => void, onApplied?: (count: number) => void }} */
	let {
		show = false,
		runId = '',
		targetLanguages = [],
		onClose = () => {},
		onApplied = () => {}
	} = $props();

	/** @type {'closed'|'configuring'|'previewing'|'preview_error'|'confirming'|'applying'|'applied'|'apply_error'} */
	let uxState = $state('closed');

	let findPattern = $state('');
	let replacementText = $state('');
	let isRegex = $state(false);
	let targetLanguage = $state('');
	let affectedRecords = $state([]);
	let applyCount = $state(0);
	let errorMessage = $state('');
	let submitToDict = $state(false);
	let usageNotes = $state('');

	$effect(() => {
		if (show) {
			uxState = 'configuring';
			findPattern = '';
			replacementText = '';
			isRegex = false;
			targetLanguage = '';
			affectedRecords = [];
			applyCount = 0;
			errorMessage = '';
			submitToDict = false;
			usageNotes = '';
		} else {
			uxState = 'closed';
		}
	});

	/** Preview affected records */
	async function handlePreview() {
		if (!findPattern.trim()) {
			addToast(_('translate.bulk_replace.find_pattern_required'), 'warning');
			return;
		}
		if (!targetLanguage) {
			addToast(_('translate.bulk_replace.target_language_required'), 'warning');
			return;
		}
		uxState = 'previewing';
		errorMessage = '';
		try {
			const result = await bulkReplacePreview(runId, {
				pattern: findPattern,
				is_regex: isRegex,
				replacement_text: replacementText,
				target_language: targetLanguage
			});
			affectedRecords = result?.items || result?.records || [];
			applyCount = affectedRecords.length;
			uxState = 'previewing';
		} catch (err) {
			errorMessage = err?.message || _('translate.bulk_replace.preview_failed');
			uxState = 'preview_error';
			addToast(errorMessage, 'error');
		}
	}

	/** Open confirmation */
	function handleShowConfirm() {
		uxState = 'confirming';
	}

	/** Cancel confirmation, back to preview */
	function handleCancelConfirm() {
		uxState = 'previewing';
	}

	/** Apply the bulk replacement */
	async function handleApply() {
		uxState = 'applying';
		try {
			const result = await bulkFindReplace(runId, {
				pattern: findPattern,
				is_regex: isRegex,
				replacement_text: replacementText,
				target_language: targetLanguage,
				submit_to_dictionary: submitToDict,
				usage_notes: usageNotes || undefined,
				submit_to_dictionary_with_context: submitToDict
			});
			const changed = result?.changed || result?.affected || applyCount;
			uxState = 'applied';
			onApplied(changed);
			addToast(_('translate.bulk_replace.applied_toast').replace('{count}', changed), 'success');
		} catch (err) {
			errorMessage = err?.message || _('translate.bulk_replace.apply_failed');
			uxState = 'apply_error';
			addToast(errorMessage, 'error');
		}
	}

	function handleClose() {
		onClose();
	}

	function previewAfter(row) {
		if (!replacementText && !isRegex) return '';
		if (isRegex) {
			try {
				const re = new RegExp(findPattern, 'g');
				return (row.final_value || row.translated_value || '').replace(re, replacementText);
			} catch {
				return row.final_value || row.translated_value || '';
			}
		}
		return (row.final_value || row.translated_value || '').split(findPattern).join(replacementText);
	}
</script>

{#if show}
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
		onclick={handleClose}
	>
		<div
			class="bg-white rounded-xl shadow-2xl w-full max-w-2xl mx-4 max-h-[85vh] flex flex-col"
			onclick={(e) => e.stopPropagation()}
			role="dialog"
			aria-modal="true"
			aria-label={$t.translate?.bulk_replace?.title}
		>
			<!-- Header -->
			<div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 flex-shrink-0">
				<h2 class="text-lg font-semibold text-gray-900">{$t.translate?.bulk_replace?.title}</h2>
				<button
					onclick={handleClose}
					class="p-1 text-gray-400 hover:text-gray-600 rounded-lg hover:bg-gray-100 transition-colors"
					aria-label={$t.translate?.bulk_replace?.close}
				>
					<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
						<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
					</svg>
				</button>
			</div>

			<!-- Body (scrollable) -->
			<div class="px-6 py-4 overflow-y-auto flex-1 space-y-4">

				<!-- Configuring State -->
				{#if uxState === 'configuring' || uxState === 'previewing' || uxState === 'preview_error'}
					<!-- Find Pattern -->
					<div>
						<label class="block text-sm font-medium text-gray-700 mb-1">{$t.translate?.bulk_replace?.find_pattern}</label>
						<div class="flex gap-2">
							<input
								type="text"
								bind:value={findPattern}
								placeholder={$t.translate?.bulk_replace?.find_placeholder}
								class="flex-1 px-3 py-2 border border-gray-300 rounded-lg text-sm focus-visible:ring-2 focus-visible:ring-primary-ring focus-visible:border-primary-ring"
								onkeydown={(e) => e.key === 'Enter' && handlePreview()}
							/>
							<label class="flex items-center gap-1.5 px-3 py-2 border border-gray-300 rounded-lg text-sm cursor-pointer hover:bg-gray-50 transition-colors">
								<input
									type="checkbox"
									bind:checked={isRegex}
									class="rounded"
								/>
								<span class="text-gray-600 font-mono text-xs">.*</span>
								<span class="text-gray-600 text-xs">{$t.translate?.bulk_replace?.regex}</span>
							</label>
						</div>
					</div>

					<!-- Replacement Text -->
					<div>
						<label class="block text-sm font-medium text-gray-700 mb-1">{$t.translate?.bulk_replace?.replace_with}</label>
						<input
							type="text"
							bind:value={replacementText}
							placeholder={$t.translate?.bulk_replace?.replace_placeholder}
							class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus-visible:ring-2 focus-visible:ring-primary-ring focus-visible:border-primary-ring"
							onkeydown={(e) => e.key === 'Enter' && handlePreview()}
						/>
					</div>

					<!-- Target Language -->
					<div>
						<label class="block text-sm font-medium text-gray-700 mb-1">{$t.translate?.bulk_replace?.target_language}</label>
						<select
							bind:value={targetLanguage}
							class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
						>
							<option value="">{$t.translate?.bulk_replace?.select_language}</option>
							{#each targetLanguages as lang}
								<option value={lang}>{lang}</option>
							{/each}
						</select>
					</div>

					<!-- Preview button -->
					<button
						onclick={handlePreview}
						disabled={!findPattern.trim() || !targetLanguage}
						class="w-full px-4 py-2 bg-primary text-white rounded-lg hover:bg-primary-hover disabled:opacity-50 transition-colors text-sm font-medium"
					>
						{$t.translate?.bulk_replace?.preview_affected}
					</button>
				{/if}

				<!-- Preview Error -->
				{#if uxState === 'preview_error'}
					<div class="bg-destructive-light border-destructive-light rounded-lg p-3">
						<p class="text-sm text-red-700">{errorMessage}</p>
					</div>
				{/if}

				<!-- Preview Table -->
				{#if uxState === 'previewing' && affectedRecords.length > 0}
					<div>
						<div class="flex items-center justify-between mb-2">
							<h3 class="text-sm font-medium text-gray-700">
								{$t.translate?.bulk_replace?.preview_count.replace('{count}', affectedRecords.length)}
							</h3>
							<button
								onclick={handleShowConfirm}
								class="px-4 py-1.5 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors text-sm font-medium"
							>
								{$t.translate?.bulk_replace?.apply_changes}
							</button>
						</div>
						<div class="max-h-60 overflow-y-auto border border-gray-200 rounded-lg">
							<table class="min-w-full divide-y divide-gray-200 text-xs">
								<thead class="bg-gray-50 sticky top-0">
									<tr>
										<th class="px-3 py-2 text-left font-medium text-gray-500 uppercase">{$t.translate?.bulk_replace?.table_number}</th>
										<th class="px-3 py-2 text-left font-medium text-gray-500 uppercase">{$t.translate?.bulk_replace?.table_before}</th>
										<th class="px-3 py-2 text-left font-medium text-gray-500 uppercase">{$t.translate?.bulk_replace?.table_after}</th>
									</tr>
								</thead>
								<tbody class="divide-y divide-gray-100">
									{#each affectedRecords.slice(0, 100) as row, i}
										<tr class="hover:bg-gray-50">
											<td class="px-3 py-2 text-gray-400">{i + 1}</td>
											<td class="px-3 py-2 text-gray-700 max-w-xs truncate">{row.final_value || row.translated_value || ''}</td>
											<td class="px-3 py-2 text-green-700 font-medium max-w-xs truncate">{previewAfter(row)}</td>
										</tr>
									{/each}
								</tbody>
							</table>
							{#if affectedRecords.length > 100}
								<div class="px-3 py-2 text-xs text-gray-400 bg-gray-50 border-t border-gray-200">
									{$t.translate?.bulk_replace?.showing_first.replace('{shown}', 100).replace('{total}', affectedRecords.length)}
								</div>
							{/if}
						</div>
					</div>
				{/if}

				{#if uxState === 'previewing' && affectedRecords.length === 0}
					<div class="bg-gray-50 border border-gray-200 rounded-lg p-6 text-center">
						<p class="text-sm text-gray-500">{$t.translate?.bulk_replace?.no_matching}</p>
						<p class="text-xs text-gray-400 mt-1">{$t.translate?.bulk_replace?.no_matching_hint}</p>
					</div>
				{/if}

				<!-- Confirmation State -->
				{#if uxState === 'confirming'}
					<div class="bg-amber-50 border border-amber-200 rounded-lg p-4">
						<div class="flex items-start gap-3">
							<svg class="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
								<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
							</svg>
							<div class="flex-1">
								<p class="text-sm font-medium text-amber-800">
									{$t.translate?.bulk_replace?.confirm_title.replace('{count}', applyCount)}
								</p>
								<p class="text-xs text-amber-700 mt-1">
									{$t.translate?.bulk_replace?.confirm_body.replace('{language}', targetLanguage)}
								</p>

								<!-- Submit to Dictionary checkbox -->
								<div class="mt-3 space-y-2">
									<label class="flex items-center gap-2 text-sm text-gray-700 cursor-pointer">
										<input type="checkbox" bind:checked={submitToDict} class="rounded" />
										<span>{$t.translate?.bulk_replace?.submit_to_dict}</span>
									</label>
									{#if submitToDict}
										<textarea
											bind:value={usageNotes}
											placeholder={$t.translate?.bulk_replace?.usage_notes_placeholder}
											class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm"
											rows="2"
										></textarea>
									{/if}
								</div>

								<div class="flex gap-2 mt-3">
									<button
										onclick={handleCancelConfirm}
										class="px-3 py-1.5 text-sm border border-gray-300 text-gray-700 rounded-lg hover:bg-white transition-colors"
									>
										{$t.translate?.bulk_replace?.cancel}
									</button>
									<button
										onclick={handleApply}
										class="px-3 py-1.5 text-sm bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors"
									>
										{$t.translate?.bulk_replace?.apply_count.replace('{count}', applyCount)}
									</button>
								</div>
							</div>
						</div>
					</div>
				{/if}

				<!-- Applying State -->
				{#if uxState === 'applying'}
					<div class="flex items-center justify-center gap-3 py-8">
						<div class="animate-spin rounded-full h-6 w-6 border-b-2 border-amber-600" />
						<span class="text-sm text-gray-600">{$t.translate?.bulk_replace?.applying}</span>
					</div>
				{/if}

				<!-- Applied State -->
				{#if uxState === 'applied'}
					<div class="bg-green-50 border border-green-200 rounded-lg p-6 text-center">
						<svg class="w-12 h-12 text-green-500 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
							<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
						</svg>
						<p class="text-sm font-medium text-green-800">{$t.translate?.bulk_replace?.applied_title}</p>
						<p class="text-xs text-green-600 mt-1">{$t.translate?.bulk_replace?.applied_body.replace('{count}', applyCount)}</p>
						<button
							onclick={handleClose}
							class="mt-4 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm"
						>
							{$t.translate?.bulk_replace?.done}
						</button>
					</div>
				{/if}

				<!-- Apply Error State -->
				{#if uxState === 'apply_error'}
					<div class="bg-destructive-light border-destructive-light rounded-lg p-3">
						<p class="text-sm text-red-700 mb-2">{errorMessage}</p>
						<div class="flex gap-2">
							<button
								onclick={handleShowConfirm}
								class="px-3 py-1.5 text-sm bg-destructive text-white rounded-lg hover:bg-destructive-hover transition-colors"
							>
								{$t.translate?.bulk_replace?.retry}
							</button>
							<button
								onclick={handleClose}
								class="px-3 py-1.5 text-sm border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
							>
								{$t.translate?.bulk_replace?.cancel}
							</button>
						</div>
					</div>
				{/if}

			</div>

			<!-- Footer (always visible) -->
			<div class="px-6 py-3 border-t border-gray-200 flex justify-end gap-2 flex-shrink-0">
				<button
					onclick={handleClose}
					class="px-4 py-2 text-sm text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors"
				>
					{$t.translate?.bulk_replace?.close}
				</button>
			</div>
		</div>
	</div>
{/if}
<!-- #endregion BulkReplaceModal -->
