<template>
  <div class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4" @click.self="emit('close')">
    <div class="flex max-h-[90vh] w-full max-w-2xl flex-col gap-3 overflow-y-auto rounded-lg border border-border bg-surface-1 p-4">
      <header class="flex items-center gap-2">
        <Rocket :size="16" class="text-accent" />
        <h2 class="font-semibold text-fg">{{ t('launch.title') }}</h2>
        <span v-if="targetLabel" class="rounded bg-surface-2 px-1.5 py-0.5 font-mono text-[11px] text-fg-muted">{{ targetLabel }}</span>
        <button class="btn ml-auto text-xs" @click="emit('close')">{{ t('common.cancel') }}</button>
      </header>

      <p class="text-xs text-fg-subtle">{{ t('launch.hint') }}</p>

      <!-- lignes de commandes éditables -->
      <div class="flex flex-col gap-2">
        <div v-for="(c, i) in rows" :key="c.id" class="flex items-center gap-2">
          <input
            v-model="c.enabled"
            type="checkbox"
            class="size-4 shrink-0 accent-[var(--color-accent-solid)]"
            :title="t('launch.enabledTitle')"
          />
          <input v-model="c.label" class="input w-28 shrink-0 text-xs" :placeholder="t('launch.labelPlaceholder')" />
          <input v-model="c.run" class="input min-w-0 flex-1 font-mono text-xs" :placeholder="t('launch.runPlaceholder')" />
          <input v-model="c.cwd" class="input w-24 shrink-0 font-mono text-xs" :placeholder="t('launch.cwdPlaceholder')" />
          <button type="button" class="btn shrink-0 px-1.5" :title="t('launch.remove')" @click="removeRow(i)">
            <Trash2 :size="13" />
          </button>
        </div>
        <p v-if="rows.length === 0" class="rounded border border-dashed border-border px-3 py-4 text-center text-xs text-fg-subtle">
          {{ t('launch.empty') }}
        </p>
      </div>

      <div class="flex flex-wrap items-center gap-2">
        <button type="button" class="btn inline-flex items-center gap-1 text-xs" @click="addRow">
          <Plus :size="13" /> {{ t('launch.add') }}
        </button>
        <button type="button" class="btn inline-flex items-center gap-1 text-xs" :disabled="detecting" @click="detect">
          <Sparkles :size="13" /> {{ detecting ? t('common.working') : t('launch.detect') }}
        </button>
      </div>

      <p v-if="errorMsg" class="text-xs text-danger">{{ errorMsg }}</p>

      <footer class="mt-1 flex items-center gap-2 border-t border-border pt-3">
        <button type="button" class="btn text-xs" :disabled="saving || working" @click="onSave">
          {{ saving ? t('common.working') : t('launch.save') }}
        </button>
        <button
          type="button"
          class="btn-primary ml-auto inline-flex items-center gap-1.5"
          :disabled="working || saving || enabledCount === 0"
          @click="onStart"
        >
          <Play :size="14" />
          {{ working ? t('common.working') : t('launch.start', { n: enabledCount }) }}
        </button>
      </footer>
    </div>
  </div>
</template>

<script setup lang="ts">
// « Démarrer le projet » : édite les commandes de démarrage d'un repo (label / commande / sous-dossier
// / activée), détecte des suggestions (package.json/Procfile/docker-compose), enregistre, et lance
// un terminal par commande activée (ide.openTerminal en boucle). Le worktree cible est passé en prop.
import { computed, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Play, Plus, Rocket, Sparkles, Trash2 } from '@lucide/vue';
import type { LaunchCommand } from '@arboretum/shared';
import { useWorktreesStore } from '../../../stores/worktrees';
import { useSessionsStore } from '../../../stores/sessions';
import { useIdeStore } from '../../../stores/ide';
import { useToastsStore } from '../../../stores/toasts';

const props = defineProps<{ repoId: string; worktreePath?: string; targetLabel?: string }>();
const emit = defineEmits<{ close: [] }>();

const { t } = useI18n();
const worktrees = useWorktreesStore();
const sessions = useSessionsStore();
const ide = useIdeStore();
const toasts = useToastsStore();

// Copie éditable locale des commandes du repo (jamais muter le store directement).
const rows = ref<LaunchCommand[]>([]);
const detecting = ref(false);
const saving = ref(false);
const working = ref(false);
const errorMsg = ref<string | null>(null);

const enabledCount = computed(() => rows.value.filter((c) => c.enabled && c.run.trim() !== '').length);

function newId(): string {
  return globalThis.crypto?.randomUUID?.() ?? `lc-${Date.now()}-${rows.value.length}`;
}

onMounted(async () => {
  const repo = worktrees.repos.find((r) => r.id === props.repoId);
  rows.value = (repo?.launchCommands ?? []).map((c) => ({ ...c }));
  // Auto-détection au premier ouvert si aucune commande n'est encore définie.
  if (rows.value.length === 0) await detect();
});

function addRow(): void {
  rows.value = [...rows.value, { id: newId(), label: '', run: '', enabled: true }];
}
function removeRow(i: number): void {
  rows.value = rows.value.filter((_, idx) => idx !== i);
}

async function detect(): Promise<void> {
  if (detecting.value) return;
  detecting.value = true;
  errorMsg.value = null;
  try {
    const suggestions = await worktrees.detectLaunch(props.repoId, props.worktreePath);
    // Fusion : n'ajoute que les commandes dont le `run` n'est pas déjà présent.
    const known = new Set(rows.value.map((c) => c.run.trim()));
    const fresh = suggestions.filter((s) => !known.has(s.run.trim()));
    if (fresh.length === 0 && suggestions.length > 0) toasts.info(t('launch.detectNone'));
    rows.value = [...rows.value, ...fresh.map((c) => ({ ...c, id: newId() }))];
  } catch (err) {
    errorMsg.value = err instanceof Error ? err.message : String(err);
  } finally {
    detecting.value = false;
  }
}

/** Normalise avant persistance : trim, retire les lignes sans commande, enlève cwd vide. */
function normalized(): LaunchCommand[] {
  return rows.value
    .map((c) => ({
      id: c.id,
      label: c.label.trim() || c.run.trim().slice(0, 24),
      run: c.run.trim(),
      enabled: c.enabled,
      ...(c.cwd && c.cwd.trim() !== '' ? { cwd: c.cwd.trim() } : {}),
    }))
    .filter((c) => c.run !== '');
}

async function persist(): Promise<void> {
  const cmds = normalized();
  await worktrees.updateRepoLaunchCommands(props.repoId, cmds);
  rows.value = cmds.map((c) => ({ ...c }));
}

async function onSave(): Promise<void> {
  if (saving.value) return;
  saving.value = true;
  errorMsg.value = null;
  try {
    await persist();
    toasts.success(t('launch.saved'));
  } catch (err) {
    errorMsg.value = err instanceof Error ? err.message : String(err);
  } finally {
    saving.value = false;
  }
}

async function onStart(): Promise<void> {
  if (working.value || enabledCount.value === 0) return;
  working.value = true;
  errorMsg.value = null;
  try {
    // On enregistre d'abord (les ids persistés doivent correspondre aux commandIds envoyés).
    await persist();
    const ids = normalized().filter((c) => c.enabled).map((c) => c.id);
    const res = await sessions.startLaunch(props.repoId, {
      commandIds: ids,
      ...(props.worktreePath ? { worktreePath: props.worktreePath } : {}),
    });
    for (const s of res.sessions) ide.openTerminal(s.id);
    if (res.skipped.length > 0) toasts.info(t('launch.partial', { started: res.sessions.length, skipped: res.skipped.length }));
    else toasts.success(t('launch.started', { n: res.sessions.length }));
    emit('close');
  } catch (err) {
    errorMsg.value = err instanceof Error ? err.message : String(err);
  } finally {
    working.value = false;
  }
}
</script>
