<!-- #region RunTabContent [C:3] [TYPE Component] [SEMANTICS translate, run, execution, progress, metrics] -->
<!-- @ingroup Translate -->
<!-- @BRIEF Run tab — translation execution with incremental/full mode selection, progress
     tracking via TranslationRunProgress, job metrics summary, and run history with
     trigger type, duration, cache rate, and expandable details. -->
<!-- @LAYER UI -->
<!-- @RELATION DEPENDS_ON -> [TranslationRunProgress] -->
<!-- @RELATION DEPENDS_ON -> [TranslationRunResult] -->
<!-- @RELATION DEPENDS_ON -> [TranslateMetricsRoutesModule] -->
<!-- @RELATION BINDS_TO -> [translationRunStore] -->
<!-- @UX_STATE Idle — no run active, run cards visible -->
<!-- @UX_STATE Running — TranslationRunProgress bar visible, cards show active state -->
<!-- @UX_STATE Completed — run history list with expandable details, summary metrics bar -->
<!-- @UX_STATE Error — error banner above run history -->
<!-- @UX_FEEDBACK Toast on status change / run error / run complete -->
<!-- @UX_FEEDBACK BulkReplace modal button in recent runs header -->
<!-- @UX_FEEDBACK Summary metrics bar with success rate, tokens, cost, avg duration -->
<!-- @UX_RECOVERY Retry button on TranslationRunProgress for failed runs -->
<!-- @UX_REACTIVITY Props -> $props() for config/state, callbacks for actions -->
<!-- @UX_REACTIVITY LocalState -> $state(jobMetrics, metricsLoading) from fetchJobMetrics -->
<script lang="ts">
  import { getT } from '$lib/i18n/index.svelte.js';
  import { addToast } from '$lib/toasts.svelte.js';
  import { updateJob, fetchJobMetrics } from '$lib/api/translate.js';
  import HelpTooltip from '$lib/ui/HelpTooltip.svelte';
  import TranslationRunProgress from './TranslationRunProgress.svelte';
  import TranslationRunResult from './TranslationRunResult.svelte';

  let {
    status = $bindable('DRAFT'),
    jobId = '',
    isRunning = false,
    isFullRun = false,
    runError = null,
    currentRunId = null,
    runComplete = false,
    completedRuns = [],
    expandedRunIds = [],
    showPageBulkReplace = $bindable(false),
    schemaValidated = false,
    onTriggerRun = (_isFull) => {},
    onRetryRun = () => {},
    onRetryInsert = () => {},
    onLoadRunHistory = () => {},
    onToggleRunDetails = (_id) => {},
    onGoToTargetTab = () => {},
    getJobStatusLabel = (s) => s,
  } = $props();

  // Job metrics state (from fetchJobMetrics)
  let jobMetrics = $state(null);
  let metricsLoading = $state(false);
  let metricsError = $state(null);

  // Confirmation dialog state
  let showConfirmDialog = $state(false);
  let pendingRunFull = $state(false);

  /** Normalize raw backend error messages to user-friendly text */
  function normalizeError(raw: string): string {
    if (!raw) return _t.translate?.config?.error_generic || 'An error occurred';
    const lower = raw.toLowerCase();
    if (lower.includes('database') && (lower.includes('does not exist') || lower.includes('unknown_database'))) {
      return _t.translate?.config?.error_db_not_found || 'Target database not found. Check your connection settings.';
    }
    if (lower.includes('connection') && (lower.includes('refused') || lower.includes('failed') || lower.includes('timeout'))) {
      return _t.translate?.config?.error_connection_failed || 'Failed to connect to the database. Check your connection settings.';
    }
    // Strip internal details (URLs, stack traces, exception codes)
    if (raw.length > 120) {
      return _t.translate?.config?.error_normalized || 'Translation execution error';
    }
    return raw;
  }

  /** Get color class for success rate percentage */
  function getSuccessRateColor(pct: number): string {
    if (pct >= 90) return 'text-success bg-success-light';
    if (pct >= 70) return 'text-warning bg-warning-light';
    return 'text-destructive bg-destructive-light';
  }

  /** Copy run ID to clipboard */
  async function copyRunId(runId: string) {
    try {
      await navigator.clipboard.writeText(runId);
      addToast(_t.translate?.config?.copy_success || 'ID copied', 'success');
    } catch {
      addToast(_t.translate?.config?.copy_failed || 'Failed to copy', 'error');
    }
  }

  /** Open confirmation dialog */
  function confirmRun(full: boolean) {
    pendingRunFull = full;
    showConfirmDialog = true;
  }

  /** Execute run after confirmation */
  function executeConfirmedRun() {
    showConfirmDialog = false;
    onTriggerRun(pendingRunFull);
  }

  $effect(() => {
    if (!jobId) return;
    loadJobMetrics();
  });

  async function loadJobMetrics() {
    metricsLoading = true;
    metricsError = null;
    try {
      const data = await fetchJobMetrics(jobId);
      jobMetrics = data;
    } catch (e) {
      metricsError = e?.message || 'Failed to load metrics';
      jobMetrics = null;
    } finally {
      metricsLoading = false;
    }
  }

  /** Compute duration seconds from started_at / completed_at. */
  function calcDuration(seconds) {
    if (!seconds && seconds !== 0) return null;
    if (seconds < 1) return '<1';
    return seconds.toFixed(1);
  }

  function getRunDuration(run) {
    if (!run.started_at) return null;
    const start = new Date(run.started_at).getTime();
    const end = run.completed_at ? new Date(run.completed_at).getTime() : Date.now();
    return calcDuration((end - start) / 1000);
  }

  function getTriggerLabel(trigger) {
    const labels = {
      manual: _t.translate?.run?.trigger_manual,
      scheduled: _t.translate?.run?.trigger_scheduled,
      retry: _t.translate?.run?.trigger_retry,
      baseline_expired: _t.translate?.run?.trigger_baseline_expired,
    };
    return labels[trigger] || trigger || _t.translate?.run?.trigger_manual;
  }

  async function handleMarkReady() {
    try {
      await updateJob(jobId, { status: 'READY' });
      status = 'READY';
      addToast(getT()?.translate?.config?.job_updated, 'success');
    } catch (e) {
      addToast(e?.message || 'Failed to update status', 'error');
    }
  }

  // @RATIONALE Svelte 5 store detection fails for `$t` in deeply nested templates.
  //             Use getT() + $derived to keep reactivity to locale changes.
  const _t = $derived(getT());
</script>

<section class="bg-surface-card border border-border rounded-lg p-6">
  <h3 class="text-lg font-semibold text-text mb-4">{_t.translate?.config?.run_translation}</h3>

  <!-- Status display + transition -->
  <div class="flex items-center gap-3 mb-4 p-3 bg-surface-muted rounded-lg">
    <span class="text-sm text-text-muted">{_t.translate?.config?.status}:</span>
    <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
      {status === 'READY' ? 'bg-success-light text-success' : ''}
      {status === 'DRAFT' ? 'bg-warning-light text-warning' : ''}
      {status === 'ACTIVE' ? 'bg-success-light text-success' : ''}
      {status === 'RUNNING' ? 'bg-primary-light text-primary' : ''}
      {status === 'COMPLETED' ? 'bg-success-light text-success' : ''}
      {status === 'FAILED' ? 'bg-destructive-light text-destructive' : ''}">
      {getJobStatusLabel(status)}
    </span>
    {#if status === 'DRAFT'}
      <button
        onclick={handleMarkReady}
        class="ml-auto px-3 py-1 text-xs bg-primary text-white rounded hover:bg-primary-hover transition-colors"
      >
        {_t.translate?.config?.mark_ready || 'Mark as READY'}
      </button>
    {/if}
  </div>

  <div class="space-y-4">
    <!-- Run mode selection: two cards -->
    <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
      <!-- Incremental run card -->
      <div class="border border-success rounded-lg p-4 {isRunning && !isFullRun ? 'bg-success-light' : 'bg-surface-card'}">
        <div class="flex items-start gap-3">
          <div class="flex-shrink-0 w-8 h-8 rounded-full bg-success-light flex items-center justify-center">
            <svg class="w-4 h-4 text-success" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
            </svg>
          </div>
          <div class="flex-1 min-w-0">
            <h3 class="text-sm font-semibold text-text flex items-center gap-1">
              {_t.translate?.config?.run_incremental}
              <HelpTooltip text={_t.translate?.config?.help_incremental || ''} />
            </h3>
            <p class="text-xs text-text-muted mt-1">{_t.translate?.config?.run_incremental_desc}</p>
            <button
              onclick={() => confirmRun(false)}
              disabled={isRunning || status === 'DRAFT' || !schemaValidated}
              class="mt-3 px-5 py-1.5 text-sm font-medium bg-success text-white rounded-lg hover:bg-success disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
            >
              {isRunning && !isFullRun ? _t.translate?.config?.running : _t.translate?.config?.run_translation}
            </button>
            {#if !schemaValidated}
              <div class="mt-1.5">
                <button onclick={onGoToTargetTab} class="text-xs text-warning hover:underline cursor-pointer">{_t.translate?.target_schema?.validate_first || 'Please verify target schema first'}</button>
              </div>
            {/if}
          </div>
        </div>
      </div>

      <!-- Full run card -->
      <div class="border border-warning rounded-lg p-4 {isRunning && isFullRun ? 'bg-warning-light' : 'bg-surface-card'}">
        <div class="flex items-start gap-3">
          <div class="flex-shrink-0 w-8 h-8 rounded-full bg-primary-light flex items-center justify-center">
            <svg class="w-4 h-4 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
            </svg>
          </div>
          <div class="flex-1 min-w-0">
            <h3 class="text-sm font-semibold text-text flex items-center gap-1">
              {_t.translate?.config?.run_full}
              <HelpTooltip text={_t.translate?.config?.help_full || ''} />
            </h3>
            <p class="text-xs text-text-muted mt-1">{_t.translate?.config?.run_full_desc}</p>
            <button
              onclick={() => confirmRun(true)}
              disabled={isRunning || status === 'DRAFT' || !schemaValidated}
              class="mt-3 px-5 py-1.5 text-sm font-medium bg-warning text-white rounded-lg hover:bg-warning-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
            >
              {isRunning && isFullRun ? _t.translate?.config?.running : _t.translate?.config?.full_translate}
            </button>
            {#if !schemaValidated}
              <div class="mt-1.5">
                <button onclick={onGoToTargetTab} class="text-xs text-warning hover:underline cursor-pointer">{_t.translate?.target_schema?.validate_first || 'Please verify target schema first'}</button>
              </div>
            {/if}
          </div>
        </div>
      </div>
    </div>

    {#if runError}
      <div class="bg-destructive-light border border-destructive-light rounded-lg p-3">
        <p class="text-sm text-destructive">{normalizeError(runError)}</p>
      </div>
    {/if}

    {#if currentRunId && !runComplete}
      <TranslationRunProgress
        runId={currentRunId}
        onRetry={onRetryRun}
        onRetryInsert={onRetryInsert}
      />
    {/if}

    <!-- Summary metrics bar -->
    {#if jobMetrics}
      <div class="bg-surface-card border border-border rounded-lg p-4">
        <div class="flex items-center justify-between mb-3">
          <h4 class="text-xs text-text-muted uppercase font-medium">{_t.translate?.run?.sum_metrics_title}</h4>
          <button
            onclick={loadJobMetrics}
            disabled={metricsLoading}
            class="text-xs text-primary hover:underline disabled:opacity-50 flex items-center gap-1"
          >
            {#if metricsLoading}
              <svg class="w-3 h-3 animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
            {:else}
              <svg class="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
            {/if}
            {_t.translate?.config?.refresh_metrics || 'Refresh'}
          </button>
        </div>
        <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
          <div class="bg-surface-muted rounded p-2.5">
            <p class="text-xs text-text-muted flex items-center gap-1">
              {_t.translate?.run?.sum_total_runs}
              <HelpTooltip text={_t.translate?.run?.help_sum_total_runs || ''} />
            </p>
            <p class="text-lg font-bold text-text">{jobMetrics.total_runs || 0}</p>
          </div>
          <div class="rounded p-2.5 {getSuccessRateColor(jobMetrics.total_runs > 0 ? Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) : 0)}">
            <p class="text-xs flex items-center gap-1 {jobMetrics.total_runs > 0 && Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) >= 90 ? 'text-success' : jobMetrics.total_runs > 0 && Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) >= 70 ? 'text-warning' : 'text-destructive'}">
              {_t.translate?.run?.sum_success_rate}
              <HelpTooltip text={_t.translate?.run?.help_sum_success_rate || ''} />
            </p>
            <p class="text-lg font-bold {jobMetrics.total_runs > 0 && Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) >= 90 ? 'text-success' : jobMetrics.total_runs > 0 && Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) >= 70 ? 'text-warning' : 'text-destructive'}">
              {jobMetrics.total_runs > 0 ? Math.round(((jobMetrics.successful_runs || 0) / jobMetrics.total_runs) * 100) : 0}%
            </p>
          </div>
          <div class="bg-surface-muted rounded p-2.5">
            <p class="text-xs text-text-muted flex items-center gap-1">
              {_t.translate?.run?.sum_total_records}
              <HelpTooltip text={_t.translate?.run?.help_sum_total_records || ''} />
            </p>
            <p class="text-lg font-bold text-text">{(jobMetrics.total_records || 0).toLocaleString()}</p>
          </div>
          <div class="bg-info-light rounded p-2.5">
            <p class="text-xs text-info flex items-center gap-1">
              {_t.translate?.run?.sum_total_tokens}
              <HelpTooltip text={_t.translate?.run?.help_sum_total_tokens || ''} />
            </p>
            <p class="text-lg font-bold text-info">{(jobMetrics.cumulative_tokens || 0).toLocaleString()}</p>
          </div>
          <div class="bg-surface-muted rounded p-2.5">
            <p class="text-xs text-text-muted flex items-center gap-1">
              {_t.translate?.run?.sum_total_cost}
              <HelpTooltip text={_t.translate?.run?.help_sum_total_cost || ''} />
            </p>
            <p class="text-lg font-bold text-text">${(jobMetrics.cumulative_cost || 0).toFixed(2)}</p>
          </div>
          <div class="bg-primary-light rounded p-2.5">
            <p class="text-xs text-primary flex items-center gap-1">
              {_t.translate?.run?.sum_avg_duration}
              <HelpTooltip text={_t.translate?.run?.help_sum_avg_duration || ''} />
            </p>
            <p class="text-lg font-bold text-primary">
              {jobMetrics.avg_duration_ms != null ? (jobMetrics.avg_duration_ms / 1000).toFixed(1) + 's' : '—'}
            </p>
          </div>
        </div>
      </div>
    {:else if metricsLoading}
      <div class="bg-surface-card border border-border rounded-lg p-4">
        <div class="grid grid-cols-6 gap-3">
          {#each Array(6) as _}
            <div class="h-16 bg-surface-muted rounded animate-pulse"></div>
          {/each}
        </div>
      </div>
    {:else if metricsError}
      <div class="bg-destructive-light border border-destructive-light rounded-lg p-3">
        <p class="text-sm text-destructive">{metricsError}</p>
      </div>
    {/if}

    {#if completedRuns.length > 0}
      <div class="mt-4">
        <div class="flex items-center justify-between mb-2">
          <h4 class="text-sm font-medium text-text">{_t.translate?.config?.recent_runs}</h4>
          <button
            onclick={() => showPageBulkReplace = true}
            class="px-3 py-1.5 text-xs bg-primary text-white rounded hover:bg-primary-hover transition-colors"
          >
            {_t.translate?.run?.bulk_replace || 'Bulk Replace'}
          </button>
        </div>
        <div class="space-y-3">
          {#each completedRuns as run}
            <div class="border border-border rounded-lg bg-surface-card">
              <div class="flex items-center justify-between gap-3 p-4">
                <div class="min-w-0">
                  <div class="flex items-center gap-2 flex-wrap">
                    <span class="text-xs text-text-muted">{_t.translate?.run?.run_id}</span>
                    <code class="text-xs text-text break-all">{run.id}</code>
                    <button
                      onclick={() => copyRunId(run.id)}
                      class="text-[11px] text-primary hover:underline shrink-0"
                      title={_t.translate?.config?.copy_id || 'Copy ID'}
                    >
                      <svg class="w-3 h-3 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
                    </button>
                    <span class="inline-flex items-center px-2 py-0.5 rounded-full text-[11px] font-medium
                      {run.status === 'COMPLETED' ? 'bg-success-light text-success' : ''}
                      {run.status === 'FAILED' ? 'bg-destructive-light text-destructive' : ''}
                      {run.status === 'CANCELLED' ? 'bg-surface-muted text-text' : ''}
                      {run.status !== 'COMPLETED' && run.status !== 'FAILED' && run.status !== 'CANCELLED' ? 'bg-warning-light text-warning' : ''}"
                    >
                      {run.status}
                    </span>
                    {#if run.trigger_type}
                      <span class="text-[11px] text-text-subtle bg-surface-muted px-1.5 py-0.5 rounded">
                        {getTriggerLabel(run.trigger_type)}
                      </span>
                    {/if}
                    {#if run.started_at}
                      <span class="text-[11px] text-text-subtle">⏱ {_t.translate?.run?.duration_label?.replace('{seconds}', getRunDuration(run))}</span>
                    {/if}
                  </div>
                  <div class="mt-2 flex flex-wrap gap-3 text-xs text-text-muted">
                    <span>{_t.translate?.run?.total}: {run.total_records || 0}</span>
                    <span class="text-success">{_t.translate?.run?.success}: {run.successful_records || 0}</span>
                    <span class="text-destructive">{_t.translate?.run?.failed}: {run.failed_records || 0}</span>
                    <span class="text-warning">{_t.translate?.run?.skipped}: {run.skipped_records || 0}</span>
                    {#if run.cache_hits}
                      <span class="text-info">
                        {_t.translate?.run?.cache_rate?.replace('{pct}', Math.round((run.cache_hits / Math.max(run.total_records || 1, 1)) * 100))}
                      </span>
                    {/if}
                  </div>
                  {#if run.error_message}
                    <p class="mt-2 text-xs text-destructive break-words">{normalizeError(run.error_message)}</p>
                  {/if}
                </div>
                <button
                  onclick={() => onToggleRunDetails(run.id)}
                  class="shrink-0 px-3 py-1.5 text-xs border border-border-strong text-text rounded hover:bg-surface-muted transition-colors"
                >
                  {expandedRunIds.includes(run.id)
                    ? (_t.translate?.run?.hide_details || 'Hide details')
                    : (_t.translate?.run?.show_details || 'Show details')}
                </button>
              </div>
              {#if expandedRunIds.includes(run.id)}
                <div class="border-t border-border p-4">
                  <TranslationRunResult runId={run.id} onRefresh={onLoadRunHistory} />
                </div>
              {/if}
            </div>
          {/each}
        </div>
      </div>
    {/if}
  </div>

  <!-- Confirmation Dialog -->
  {#if showConfirmDialog}
    <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onclick={() => showConfirmDialog = false}>
      <div class="bg-surface-card border border-border rounded-xl shadow-xl max-w-md w-full mx-4 p-6" onclick={(e) => e.stopPropagation()}>
        <h3 class="text-lg font-semibold text-text mb-2">
          {pendingRunFull
            ? (_t.translate?.config?.confirm_full_run_title || 'Run full translation?')
            : (_t.translate?.config?.confirm_run_title || 'Run translation?')}
        </h3>
        <p class="text-sm text-text-muted mb-4">
          {pendingRunFull
            ? (_t.translate?.config?.confirm_full_run_body || 'This will re-translate ALL rows from the source, ignoring the cache.')
            : (_t.translate?.config?.confirm_run_body || 'Are you sure you want to start the incremental translation?')}
        </p>
        <div class="flex justify-end gap-3">
          <button
            onclick={() => showConfirmDialog = false}
            class="px-4 py-2 border border-border-strong text-text rounded-lg hover:bg-surface-muted transition-colors text-sm"
          >
            {_t.translate?.common?.cancel || 'Cancel'}
          </button>
          <button
            onclick={executeConfirmedRun}
            class="px-4 py-2 {pendingRunFull ? 'bg-warning text-white hover:bg-warning-hover' : 'bg-primary text-white hover:bg-primary-hover'} rounded-lg transition-colors text-sm font-medium"
          >
            {_t.translate?.config?.confirm || 'Confirm'}
          </button>
        </div>
      </div>
    </div>
  {/if}
</section>
<!-- #endregion RunTabContent -->
