{% extends "base.html" %}
{% block title %}{{ _("pipelines.title") }} – DocuElevate{% endblock %}

{% block content %}
<div class="container mx-auto px-4 py-8" x-data="pipelinesApp()" x-init="init()">

  <!-- ── Header ─────────────────────────────────────────────────────────────── -->
  <div class="mb-6 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
    <div>
      <h1 class="text-3xl font-bold text-gray-900 dark:text-white flex items-center gap-2">
        <i class="fas fa-project-diagram text-blue-500" aria-hidden="true"></i>
        {{ _("pipelines.page_title") }}
      </h1>
      <p class="text-gray-500 dark:text-gray-400 text-sm mt-1">
        {{ _("pipelines.subtitle_intro") }}
        {{ _("pipelines.subtitle_system_pre") }}
        <span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1">{{ _("pipelines.system_label") }}</span>
        {{ _("pipelines.subtitle_system_post") }}
      </p>
    </div>
    <button
      type="button"
      @click="openCreatePipelineModal()"
      class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
      style="min-height:44px;"
    >
      <i class="fas fa-plus mr-2" aria-hidden="true"></i> {{ _("pipelines.new_pipeline_btn") }}
    </button>
  </div>

  <!-- ── Alert banner ───────────────────────────────────────────────────────── -->
  <!-- Two containers with static aria-live so screen readers register them on page load -->
  <div aria-live="polite" aria-atomic="true">
    <div x-show="alert.show && alert.type !== 'error'" x-transition class="mb-4" role="status">
      <div class="bg-green-50 border-green-400 text-green-800 border-l-4 p-4 rounded dark:bg-opacity-10">
        <p class="font-semibold" x-text="alert.title"></p>
        <p class="text-sm" x-text="alert.message"></p>
      </div>
    </div>
  </div>
  <div aria-live="assertive" aria-atomic="true">
    <div x-show="alert.show && alert.type === 'error'" x-transition class="mb-4" role="alert">
      <div class="bg-red-50 border-red-400 text-red-800 border-l-4 p-4 rounded dark:bg-opacity-10">
        <p class="font-semibold" x-text="alert.title"></p>
        <p class="text-sm" x-text="alert.message"></p>
      </div>
    </div>
  </div>

  <!-- ── Loading ────────────────────────────────────────────────────────────── -->
  <template x-if="loading">
    <div class="text-center py-12 text-gray-400">
      <i class="fas fa-spinner fa-spin text-3xl mb-3" aria-hidden="true"></i>
      <p>{{ _("pipelines.loading") }}</p>
    </div>
  </template>

  <!-- ── Empty state ────────────────────────────────────────────────────────── -->
  <template x-if="!loading && pipelines.length === 0">
    <div class="text-center py-16 bg-white dark:bg-gray-800 rounded-lg shadow">
      <i class="fas fa-project-diagram text-5xl text-gray-300 mb-4" aria-hidden="true"></i>
      <h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300 mb-2">{{ _("pipelines.empty_state") }}</h2>
      <p class="text-gray-500 dark:text-gray-400 mb-6">{{ _("pipelines.empty_state_hint") }}</p>
      <button
        type="button"
        @click="openCreatePipelineModal()"
        class="inline-flex items-center px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md"
        style="min-height:44px;"
      >
        <i class="fas fa-plus mr-2" aria-hidden="true"></i> {{ _("pipelines.create") }}
      </button>
    </div>
  </template>

  <!-- ── Pipeline cards ─────────────────────────────────────────────────────── -->
  <template x-if="!loading && pipelines.length > 0">
    <div class="space-y-4">
      <template x-for="pipeline in pipelines" :key="pipeline.id">
        <div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">

          <!-- Card header -->
          <div class="px-5 py-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-b border-gray-100 dark:border-gray-700">
            <div class="flex items-center gap-2 flex-wrap">
              <h2 class="text-lg font-semibold text-gray-900 dark:text-white" x-text="pipeline.name"></h2>
              <!-- Badges -->
              <template x-if="pipeline.owner_id === null">
                <span class="text-xs font-semibold text-purple-700 bg-purple-50 border border-purple-200 rounded px-1.5 py-0.5">{{ _("pipelines.system_label") }}</span>
              </template>
              <template x-if="pipeline.is_default">
                <span class="text-xs font-semibold text-green-700 bg-green-50 border border-green-200 rounded px-1.5 py-0.5">{{ _("pipelines.default_label") }}</span>
              </template>
              <template x-if="!pipeline.is_active">
                <span class="text-xs font-semibold text-gray-500 bg-gray-100 border border-gray-200 rounded px-1.5 py-0.5">{{ _("pipelines.inactive_label") }}</span>
              </template>
            </div>

            <!-- Actions -->
            <div class="flex items-center gap-2 flex-shrink-0">
              <button
                type="button"
                @click="toggleSteps(pipeline)"
                class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-gray-600 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-md"
                style="min-height:36px;"
                :aria-expanded="pipeline._expanded"
                :aria-label="`${pipeline._expanded ? 'Collapse' : 'Expand'} steps for ${pipeline.name}`"
              >
                <i class="fas fa-list-ul mr-1" aria-hidden="true"></i>
                <span x-text="(pipeline.steps || []).length + ' step' + ((pipeline.steps || []).length !== 1 ? 's' : '')"></span>
                <i :class="pipeline._expanded ? 'fa-chevron-up' : 'fa-chevron-down'" class="fas ml-1 text-xs" aria-hidden="true"></i>
              </button>
              <button
                type="button"
                @click="openEditPipelineModal(pipeline)"
                class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-blue-600 bg-blue-50 hover:bg-blue-100 rounded-md"
                style="min-height:36px;"
                :aria-label="`Edit pipeline ${pipeline.name}`"
              >
                <i class="fas fa-pencil-alt mr-1" aria-hidden="true"></i> {{ _("common.edit") }}
              </button>
              <button
                type="button"
                @click="confirmDeletePipeline(pipeline)"
                class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-red-600 bg-red-50 hover:bg-red-100 rounded-md"
                style="min-height:36px;"
                :aria-label="`Delete pipeline ${pipeline.name}`"
              >
                <i class="fas fa-trash mr-1" aria-hidden="true"></i> {{ _("common.delete") }}
              </button>
            </div>
          </div>

          <!-- Description -->
          <template x-if="pipeline.description">
            <p class="px-5 pt-3 text-sm text-gray-500 dark:text-gray-400" x-text="pipeline.description"></p>
          </template>

          <!-- Steps (collapsible) -->
          <div x-show="pipeline._expanded" x-transition class="px-5 py-4">

            <!-- Step list -->
            <template x-if="(pipeline.steps || []).length === 0">
              <p class="text-sm text-gray-400 italic mb-3">{{ _("pipelines.no_steps") }}</p>
            </template>

            <template x-if="(pipeline.steps || []).length > 0">
              <ol class="space-y-2 mb-4" role="list" :aria-label="`Steps for ${pipeline.name}`">
                <template x-for="(step, idx) in (pipeline.steps || [])" :key="step.id">
                  <li class="flex items-center justify-between bg-gray-50 dark:bg-gray-700 rounded-md px-4 py-2.5 gap-3">
                    <div class="flex items-center gap-3 min-w-0">
                      <span class="flex-shrink-0 w-6 h-6 rounded-full bg-blue-100 text-blue-600 text-xs font-bold flex items-center justify-center" x-text="idx + 1" aria-hidden="true"></span>
                      <div class="min-w-0">
                        <p class="text-sm font-medium text-gray-800 dark:text-gray-200 truncate" x-text="step.label || stepTypeLabel(step.step_type)"></p>
                        <p class="text-xs text-gray-400 truncate" x-text="step.step_type"></p>
                      </div>
                      <template x-if="!step.enabled">
                        <span class="text-xs text-gray-400 bg-gray-200 rounded px-1.5 py-0.5 flex-shrink-0">{{ _("pipelines.disabled_label") }}</span>
                      </template>
                    </div>
                    <div class="flex items-center gap-1.5 flex-shrink-0">
                      <button
                        type="button"
                        @click="openEditStepModal(pipeline, step)"
                        class="p-1.5 text-blue-500 hover:bg-blue-50 dark:hover:bg-blue-900 rounded"
                        style="min-height:36px;min-width:36px;"
                        :aria-label="`Edit step ${step.label || step.step_type}`"
                      ><i class="fas fa-pencil-alt text-xs" aria-hidden="true"></i></button>
                      <button
                        type="button"
                        @click="moveStep(pipeline, idx, -1)"
                        :disabled="idx === 0"
                        class="p-1.5 text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-600 rounded disabled:opacity-30"
                        style="min-height:36px;min-width:36px;"
                        :aria-label="`Move step up: ${step.label || step.step_type}`"
                      ><i class="fas fa-arrow-up text-xs" aria-hidden="true"></i></button>
                      <button
                        type="button"
                        @click="moveStep(pipeline, idx, 1)"
                        :disabled="idx === (pipeline.steps || []).length - 1"
                        class="p-1.5 text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-600 rounded disabled:opacity-30"
                        style="min-height:36px;min-width:36px;"
                        :aria-label="`Move step down: ${step.label || step.step_type}`"
                      ><i class="fas fa-arrow-down text-xs" aria-hidden="true"></i></button>
                      <button
                        type="button"
                        @click="confirmDeleteStep(pipeline, step)"
                        class="p-1.5 text-red-400 hover:bg-red-50 dark:hover:bg-red-900 rounded"
                        style="min-height:36px;min-width:36px;"
                        :aria-label="`Delete step ${step.label || step.step_type}`"
                      ><i class="fas fa-times text-xs" aria-hidden="true"></i></button>
                    </div>
                  </li>
                </template>
              </ol>
            </template>

            <!-- Add step button -->
            <button
              type="button"
              @click="openAddStepModal(pipeline)"
              class="inline-flex items-center px-3 py-1.5 text-xs font-medium text-green-600 bg-green-50 hover:bg-green-100 rounded-md border border-green-200"
              style="min-height:36px;"
              :aria-label="`Add step to ${pipeline.name}`"
            >
              <i class="fas fa-plus mr-1" aria-hidden="true"></i> {{ _("pipelines.add_step_btn") }}
            </button>
          </div>

        </div>
      </template>
    </div>
  </template>


  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <!-- Modal: Create / Edit Pipeline                                         -->
  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <div
    x-show="pipelineModal.open"
    x-transition:enter="transition ease-out duration-200"
    x-transition:enter-start="opacity-0"
    x-transition:enter-end="opacity-100"
    x-transition:leave="transition ease-in duration-150"
    x-transition:leave-start="opacity-100"
    x-transition:leave-end="opacity-0"
    class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
    role="dialog"
    aria-modal="true"
    :aria-labelledby="pipelineModal.editMode ? 'editPipelineTitle' : 'createPipelineTitle'"
    @keydown.escape.window="closePipelineModal()"
  >
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-md mx-4 p-6" @click.stop>
      <h2
        :id="pipelineModal.editMode ? 'editPipelineTitle' : 'createPipelineTitle'"
        class="text-xl font-semibold text-gray-900 dark:text-white mb-5"
        x-text="pipelineModal.editMode ? 'Edit Pipeline' : 'New Pipeline'"
      ></h2>

      <form @submit.prevent="savePipeline()" novalidate>
        <div class="space-y-4">

          <!-- Name -->
          <div>
            <label for="pipelineName" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
              {{ _("common.name") }} <span aria-hidden="true" class="text-red-500">*</span>
            </label>
            <input
              id="pipelineName"
              type="text"
              x-model="pipelineModal.form.name"
              maxlength="255"
              required
              class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
              placeholder="{{ _('pipelines.name_placeholder') }}"
              autocomplete="off"
            />
          </div>

          <!-- Description -->
          <div>
            <label for="pipelineDesc" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{{ _("common.description") }}</label>
            <textarea
              id="pipelineDesc"
              x-model="pipelineModal.form.description"
              rows="2"
              maxlength="4096"
              class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white resize-none"
              placeholder="{{ _('pipelines.description_placeholder') }}"
            ></textarea>
          </div>

          <!-- Flags -->
          <div class="flex flex-col gap-2">
            <label class="inline-flex items-center gap-2 cursor-pointer">
              <input
                type="checkbox"
                x-model="pipelineModal.form.is_default"
                class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
              />
              <span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.set_default") }}</span>
            </label>
            <label class="inline-flex items-center gap-2 cursor-pointer">
              <input
                type="checkbox"
                x-model="pipelineModal.form.is_active"
                class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
              />
              <span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.active_label") }}</span>
            </label>
          </div>

          <!-- System pipeline option (admin only, create only) -->
          <template x-if="isAdmin && !pipelineModal.editMode">
            <label class="inline-flex items-center gap-2 cursor-pointer">
              <input
                type="checkbox"
                x-model="pipelineModal.form.system"
                class="rounded border-gray-300 text-purple-600 focus:ring-purple-400"
              />
              <span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.system_pipeline_label") }}</span>
            </label>
          </template>

          <!-- Error message -->
          <p x-show="pipelineModal.error" class="text-sm text-red-600" x-text="pipelineModal.error" role="alert"></p>
        </div>

        <div class="flex justify-end gap-3 mt-6">
          <button
            type="button"
            @click="closePipelineModal()"
            class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
            style="min-height:44px;"
          >{{ _("common.cancel") }}</button>
          <button
            type="submit"
            :disabled="pipelineModal.saving"
            class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-60 rounded-md"
            style="min-height:44px;"
          >
              <template x-if="pipelineModal.saving">
                <i class="fas fa-spinner fa-spin mr-1" aria-hidden="true"></i>
              </template>
            <span x-text="pipelineModal.editMode ? 'Save Changes' : 'Create'"></span>
          </button>
        </div>
      </form>
    </div>
  </div>


  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <!-- Modal: Add / Edit Step                                                -->
  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <div
    x-show="stepModal.open"
    x-transition:enter="transition ease-out duration-200"
    x-transition:enter-start="opacity-0"
    x-transition:enter-end="opacity-100"
    x-transition:leave="transition ease-in duration-150"
    x-transition:leave-start="opacity-100"
    x-transition:leave-end="opacity-0"
    class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
    role="dialog"
    aria-modal="true"
    :aria-labelledby="stepModal.editMode ? 'editStepTitle' : 'addStepTitle'"
    @keydown.escape.window="closeStepModal()"
  >
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-lg mx-4 p-6" @click.stop>
      <h2
        :id="stepModal.editMode ? 'editStepTitle' : 'addStepTitle'"
        class="text-xl font-semibold text-gray-900 dark:text-white mb-5"
        x-text="stepModal.editMode ? 'Edit Step' : 'Add Step'"
      ></h2>

      <form @submit.prevent="saveStep()" novalidate>
        <div class="space-y-4">

          <!-- Step type -->
          <div>
            <label for="stepType" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
              {{ _("pipelines.step_type_label") }} <span aria-hidden="true" class="text-red-500">*</span>
            </label>
            <select
              id="stepType"
              x-model="stepModal.form.step_type"
              :disabled="stepModal.editMode"
              class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
            >
              <option value="">{{ _("common.select_placeholder") }}</option>
              <template x-for="[key, meta] in Object.entries(stepTypes)" :key="key">
                <option :value="key" x-text="meta.label"></option>
              </template>
            </select>
            <template x-if="stepModal.form.step_type && stepTypes[stepModal.form.step_type]">
              <p class="mt-1 text-xs text-gray-400" x-text="stepTypes[stepModal.form.step_type].description"></p>
            </template>
          </div>

          <!-- Custom label -->
          <div>
            <label for="stepLabel" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
              {{ _("pipelines.custom_label_label") }} <span class="text-gray-400 font-normal">{{ _("pipelines.optional_suffix") }}</span>
            </label>
            <input
              id="stepLabel"
              type="text"
              x-model="stepModal.form.label"
              maxlength="255"
              class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
              placeholder="{{ _('pipelines.step_label_placeholder') }}"
              autocomplete="off"
            />
          </div>

          <!-- force_cloud_ocr (only shown for ocr step) -->
          <template x-if="stepModal.form.step_type === 'ocr'">
            <label class="inline-flex items-center gap-2 cursor-pointer">
              <input
                type="checkbox"
                x-model="stepModal.form.config.force_cloud_ocr"
                class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
              />
              <span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.force_cloud_ocr_label") }}</span>
            </label>
          </template>

          <!-- ocr_language (only shown for ocr step) -->
          <template x-if="stepModal.form.step_type === 'ocr'">
            <div>
              <label for="ocrLanguage" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
                {{ _("pipelines.ocr_language_label") }}
              </label>
              <select
                id="ocrLanguage"
                x-model="stepModal.form.config.ocr_language"
                class="w-full border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 dark:bg-gray-700 dark:text-white"
              >
                <option value="auto">{{ _("pipelines.ocr_auto") }}</option>
                <option value="ara">Arabic</option>
                <option value="chi_sim">Chinese (Simplified)</option>
                <option value="chi_tra">Chinese (Traditional)</option>
                <option value="ces">Czech</option>
                <option value="dan">Danish</option>
                <option value="nld">Dutch</option>
                <option value="eng">English</option>
                <option value="fin">Finnish</option>
                <option value="fra">French</option>
                <option value="deu">German</option>
                <option value="ell">Greek</option>
                <option value="heb">Hebrew</option>
                <option value="hin">Hindi</option>
                <option value="hun">Hungarian</option>
                <option value="ita">Italian</option>
                <option value="jpn">Japanese</option>
                <option value="kor">Korean</option>
                <option value="nor">Norwegian</option>
                <option value="pol">Polish</option>
                <option value="por">Portuguese</option>
                <option value="ron">Romanian</option>
                <option value="rus">Russian</option>
                <option value="spa">Spanish</option>
                <option value="swe">Swedish</option>
                <option value="tha">Thai</option>
                <option value="tur">Turkish</option>
                <option value="ukr">Ukrainian</option>
                <option value="vie">Vietnamese</option>
              </select>
              <p class="mt-1 text-xs text-gray-400">
                {{ _("pipelines.ocr_language_hint") }}
              </p>
            </div>
          </template>

          <!-- Enabled -->
          <label class="inline-flex items-center gap-2 cursor-pointer">
            <input
              type="checkbox"
              x-model="stepModal.form.enabled"
              class="rounded border-gray-300 text-blue-600 focus:ring-blue-400"
            />
            <span class="text-sm text-gray-700 dark:text-gray-300">{{ _("pipelines.enabled_label") }}</span>
          </label>

          <!-- Error -->
          <p x-show="stepModal.error" class="text-sm text-red-600" x-text="stepModal.error" role="alert"></p>
        </div>

        <div class="flex justify-end gap-3 mt-6">
          <button
            type="button"
            @click="closeStepModal()"
            class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
            style="min-height:44px;"
          >{{ _("common.cancel") }}</button>
          <button
            type="submit"
            :disabled="stepModal.saving"
            class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-60 rounded-md"
            style="min-height:44px;"
          >
            <template x-if="stepModal.saving">
              <i class="fas fa-spinner fa-spin mr-1" aria-hidden="true"></i>
            </template>
            <span x-text="stepModal.editMode ? 'Save Changes' : 'Add Step'"></span>
          </button>
        </div>
      </form>
    </div>
  </div>


  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <!-- Confirm delete dialog                                                 -->
  <!-- ═══════════════════════════════════════════════════════════════════════ -->
  <div
    x-show="confirmModal.open"
    x-transition:enter="transition ease-out duration-150"
    x-transition:enter-start="opacity-0"
    x-transition:enter-end="opacity-100"
    x-transition:leave="transition ease-in duration-100"
    x-transition:leave-start="opacity-100"
    x-transition:leave-end="opacity-0"
    class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"
    role="alertdialog"
    aria-modal="true"
    aria-labelledby="confirmTitle"
    @keydown.escape.window="confirmModal.open = false"
  >
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-sm mx-4 p-6" @click.stop>
      <h2 id="confirmTitle" class="text-lg font-semibold text-gray-900 dark:text-white mb-2" x-text="confirmModal.title"></h2>
      <p class="text-sm text-gray-600 dark:text-gray-400 mb-6" x-text="confirmModal.message"></p>
      <div class="flex justify-end gap-3">
        <button
          type="button"
          @click="confirmModal.open = false"
          class="px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-50"
          style="min-height:44px;"
        >{{ _("common.cancel") }}</button>
        <button
          type="button"
          @click="confirmModal.action(); confirmModal.open = false"
          class="px-4 py-2 text-sm font-medium text-white bg-red-600 hover:bg-red-700 rounded-md"
          style="min-height:44px;"
        >{{ _("common.delete") }}</button>
      </div>
    </div>
  </div>

</div>
{% endblock %}

{% block head_extra %}
<script>
function pipelinesApp() {
  return {
    loading: true,
    pipelines: [],
    stepTypes: {},
    isAdmin: false,

    alert: { show: false, type: 'success', title: '', message: '' },

    pipelineModal: {
      open: false,
      editMode: false,
      pipelineId: null,
      saving: false,
      error: '',
      form: { name: '', description: '', is_default: false, is_active: true, system: false },
    },

    stepModal: {
      open: false,
      editMode: false,
      pipeline: null,
      stepId: null,
      saving: false,
      error: '',
      form: { step_type: '', label: '', config: {}, enabled: true },
    },

    confirmModal: {
      open: false,
      title: '',
      message: '',
      action: () => {},
    },

    // ── Initialisation ────────────────────────────────────────────────────

    async init() {
      await Promise.all([this.fetchStepTypes(), this.fetchCurrentUser()]);
      await this.fetchPipelines();
    },

    async fetchCurrentUser() {
      try {
        const r = await fetch('/api/auth/whoami');
        if (r.ok) {
          const u = await r.json();
          this.isAdmin = !!u.is_admin;
        }
      } catch (_) {}
    },

    async fetchStepTypes() {
      try {
        const r = await fetch('/api/pipelines/step-types');
        if (r.ok) this.stepTypes = await r.json();
      } catch (_) {}
    },

    async fetchPipelines() {
      this.loading = true;
      try {
        const r = await fetch('/api/pipelines');
        if (!r.ok) throw new Error(await r.text());
        const list = await r.json();
        // Fetch steps for each pipeline
        const detailed = await Promise.all(list.map(p => this.fetchPipeline(p.id)));
        this.pipelines = detailed.map(p => ({ ...p, _expanded: false }));
      } catch (err) {
        this.showAlert('error', 'Failed to load pipelines', err.message || String(err));
      } finally {
        this.loading = false;
      }
    },

    async fetchPipeline(id) {
      const r = await fetch(`/api/pipelines/${id}`);
      if (!r.ok) throw new Error(`Pipeline ${id} not found`);
      return r.json();
    },

    // ── Helpers ───────────────────────────────────────────────────────────

    stepTypeLabel(key) {
      return this.stepTypes[key] ? this.stepTypes[key].label : key;
    },

    showAlert(type, title, message) {
      this.alert = { show: true, type, title, message };
      setTimeout(() => { this.alert.show = false; }, 6000);
    },

    toggleSteps(pipeline) {
      pipeline._expanded = !pipeline._expanded;
    },

    // ── Pipeline Modal ────────────────────────────────────────────────────

    openCreatePipelineModal() {
      this.pipelineModal = {
        open: true,
        editMode: false,
        pipelineId: null,
        saving: false,
        error: '',
        form: { name: '', description: '', is_default: false, is_active: true, system: false },
      };
    },

    openEditPipelineModal(pipeline) {
      this.pipelineModal = {
        open: true,
        editMode: true,
        pipelineId: pipeline.id,
        saving: false,
        error: '',
        form: {
          name: pipeline.name,
          description: pipeline.description || '',
          is_default: pipeline.is_default,
          is_active: pipeline.is_active,
          system: false,
        },
      };
    },

    closePipelineModal() {
      this.pipelineModal.open = false;
    },

    async savePipeline() {
      const fm = this.pipelineModal.form;
      if (!fm.name.trim()) {
        this.pipelineModal.error = 'Pipeline name is required.';
        return;
      }
      this.pipelineModal.error = '';
      this.pipelineModal.saving = true;

      try {
        let r;
        if (this.pipelineModal.editMode) {
          r = await fetch(`/api/pipelines/${this.pipelineModal.pipelineId}`, {
            method: 'PUT',
            headers: this._jsonHeaders(),
            body: JSON.stringify({
              name: fm.name.trim(),
              description: fm.description || null,
              is_default: fm.is_default,
              is_active: fm.is_active,
            }),
          });
        } else {
          const url = fm.system ? '/api/pipelines/admin/system' : '/api/pipelines';
          r = await fetch(url, {
            method: 'POST',
            headers: this._jsonHeaders(),
            body: JSON.stringify({
              name: fm.name.trim(),
              description: fm.description || null,
              is_default: fm.is_default,
              is_active: fm.is_active,
            }),
          });
        }
        if (!r.ok) {
          const e = await r.json().catch(() => ({}));
          throw new Error(e.detail || `HTTP ${r.status}`);
        }
        const saved = await r.json();
        if (this.pipelineModal.editMode) {
          const idx = this.pipelines.findIndex(p => p.id === saved.id);
          if (idx !== -1) {
            const expanded = this.pipelines[idx]._expanded;
            this.pipelines[idx] = { ...saved, steps: this.pipelines[idx].steps || [], _expanded: expanded };
          }
        } else {
          this.pipelines.push({ ...saved, steps: [], _expanded: false });
        }
        this.closePipelineModal();
        this.showAlert('success', 'Pipeline saved', `"${saved.name}" has been ${this.pipelineModal.editMode ? 'updated' : 'created'}.`);
      } catch (err) {
        this.pipelineModal.error = err.message || 'Unknown error';
      } finally {
        this.pipelineModal.saving = false;
      }
    },

    confirmDeletePipeline(pipeline) {
      this.confirmModal = {
        open: true,
        title: 'Delete pipeline?',
        message: `Are you sure you want to permanently delete "${pipeline.name}" and all its steps? This cannot be undone.`,
        action: () => this.deletePipeline(pipeline),
      };
    },

    async deletePipeline(pipeline) {
      try {
        const r = await fetch(`/api/pipelines/${pipeline.id}`, { method: 'DELETE', headers: this._csrfHeaders() });
        if (!r.ok) {
          const e = await r.json().catch(() => ({}));
          throw new Error(e.detail || `HTTP ${r.status}`);
        }
        this.pipelines = this.pipelines.filter(p => p.id !== pipeline.id);
        this.showAlert('success', 'Pipeline deleted', `"${pipeline.name}" has been deleted.`);
      } catch (err) {
        this.showAlert('error', 'Delete failed', err.message || String(err));
      }
    },

    // ── Step Modal ────────────────────────────────────────────────────────

    openAddStepModal(pipeline) {
      this.stepModal = {
        open: true,
        editMode: false,
        pipeline,
        stepId: null,
        saving: false,
        error: '',
        form: { step_type: '', label: '', config: {}, enabled: true },
      };
    },

    openEditStepModal(pipeline, step) {
      this.stepModal = {
        open: true,
        editMode: true,
        pipeline,
        stepId: step.id,
        saving: false,
        error: '',
        form: {
          step_type: step.step_type,
          label: step.label || '',
          config: { ...(step.config || {}) },
          enabled: step.enabled,
        },
      };
    },

    closeStepModal() {
      this.stepModal.open = false;
    },

    async saveStep() {
      const fm = this.stepModal.form;
      if (!fm.step_type) {
        this.stepModal.error = 'Step type is required.';
        return;
      }
      this.stepModal.error = '';
      this.stepModal.saving = true;
      const pid = this.stepModal.pipeline.id;

      try {
        let r;
        if (this.stepModal.editMode) {
          r = await fetch(`/api/pipelines/${pid}/steps/${this.stepModal.stepId}`, {
            method: 'PUT',
            headers: this._jsonHeaders(),
            body: JSON.stringify({
              step_type: fm.step_type,
              label: fm.label || null,
              config: fm.config || {},
              enabled: fm.enabled,
            }),
          });
        } else {
          r = await fetch(`/api/pipelines/${pid}/steps`, {
            method: 'POST',
            headers: this._jsonHeaders(),
            body: JSON.stringify({
              step_type: fm.step_type,
              label: fm.label || null,
              config: fm.config || {},
              enabled: fm.enabled,
            }),
          });
        }
        if (!r.ok) {
          const e = await r.json().catch(() => ({}));
          throw new Error(e.detail || `HTTP ${r.status}`);
        }
        const savedStep = await r.json();
        // Refresh the pipeline's steps
        const updated = await this.fetchPipeline(pid);
        const pIdx = this.pipelines.findIndex(p => p.id === pid);
        if (pIdx !== -1) {
          const expanded = this.pipelines[pIdx]._expanded;
          this.pipelines[pIdx] = { ...updated, _expanded: expanded };
        }
        this.closeStepModal();
        this.showAlert('success', 'Step saved', `Step "${savedStep.label || savedStep.step_type}" has been ${this.stepModal.editMode ? 'updated' : 'added'}.`);
      } catch (err) {
        this.stepModal.error = err.message || 'Unknown error';
      } finally {
        this.stepModal.saving = false;
      }
    },

    async moveStep(pipeline, idx, direction) {
      const steps = pipeline.steps || [];
      const newIdx = idx + direction;
      if (newIdx < 0 || newIdx >= steps.length) return;
      // Build the new order
      const reordered = [...steps];
      [reordered[idx], reordered[newIdx]] = [reordered[newIdx], reordered[idx]];
      const ids = reordered.map(s => s.id);
      try {
        const r = await fetch(`/api/pipelines/${pipeline.id}/steps/reorder`, {
          method: 'PUT',
          headers: this._jsonHeaders(),
          body: JSON.stringify(ids),
        });
        if (!r.ok) {
          const e = await r.json().catch(() => ({}));
          throw new Error(e.detail || `HTTP ${r.status}`);
        }
        const updated = await this.fetchPipeline(pipeline.id);
        const pIdx = this.pipelines.findIndex(p => p.id === pipeline.id);
        if (pIdx !== -1) {
          this.pipelines[pIdx] = { ...updated, _expanded: true };
        }
      } catch (err) {
        this.showAlert('error', 'Reorder failed', err.message || String(err));
      }
    },

    confirmDeleteStep(pipeline, step) {
      this.confirmModal = {
        open: true,
        title: 'Delete step?',
        message: `Remove "${step.label || step.step_type}" from pipeline "${pipeline.name}"?`,
        action: () => this.deleteStep(pipeline, step),
      };
    },

    async deleteStep(pipeline, step) {
      try {
        const r = await fetch(`/api/pipelines/${pipeline.id}/steps/${step.id}`, {
          method: 'DELETE',
          headers: this._csrfHeaders(),
        });
        if (!r.ok) {
          const e = await r.json().catch(() => ({}));
          throw new Error(e.detail || `HTTP ${r.status}`);
        }
        const updated = await this.fetchPipeline(pipeline.id);
        const pIdx = this.pipelines.findIndex(p => p.id === pipeline.id);
        if (pIdx !== -1) {
          this.pipelines[pIdx] = { ...updated, _expanded: true };
        }
        this.showAlert('success', 'Step deleted', `"${step.label || step.step_type}" removed.`);
      } catch (err) {
        this.showAlert('error', 'Delete failed', err.message || String(err));
      }
    },

    // ── Fetch helpers ─────────────────────────────────────────────────────

    _csrfToken() {
      return document.querySelector('meta[name="csrf-token"]')?.content || '';
    },

    _csrfHeaders() {
      return { 'X-CSRF-Token': this._csrfToken() };
    },

    _jsonHeaders() {
      return { 'Content-Type': 'application/json', 'X-CSRF-Token': this._csrfToken() };
    },
  };
}
</script>
{% endblock %}
