<!--
  FlowEditorDialog.vue — Global, full-screen editor dialog for Flow Templates.

  Mounted once in MainLayout; any page opens it via the useFlowEditor
  composable. This is the Odoo "inline create from anywhere" pattern.

  What it does:
    - Shows metadata header (template_name, category, applies_to, icon,
      active/inactive toggle, version badge, system badge)
    - Renders the FlowEditor visual tree bound to template.flow_definition
    - Action bar: Save / Duplicate / Delete / Close
    - Protects system templates from destructive edits (offers Duplicate)

  Performance:
    - Lazy: only renders the heavy FlowEditor when `isOpen` is true
    - Uses `markDirty` on every field blur instead of watching the whole doc
      (avoids O(n) deep-watch overhead on large flows)
-->
<template>
  <q-dialog :model-value="isOpen" @update:model-value="onModelUpdate" persistent maximized
    transition-show="slide-up" transition-hide="slide-down">
    <q-card class="flow-editor-dialog column no-wrap">
      <!-- Header -->
      <q-card-section class="fe-header">
        <div class="row items-center no-wrap">
          <q-icon :name="template?.icon || 'account_tree'" size="24px" color="primary" class="q-mr-sm" />
          <div class="col">
            <div class="text-subtitle1 text-weight-bold">
              {{ mode === 'new' ? 'Nouveau template de flow' : (template?.template_name || templateName || '') }}
            </div>
            <div class="text-caption text-grey-7">
              <span v-if="templateName">{{ templateName }}</span>
              <span v-if="template?.version" class="q-ml-sm">v{{ template.version }}</span>
              <q-badge v-if="template?.is_system" color="amber-1" text-color="amber-9" label="système"
                class="q-ml-sm" />
              <q-badge v-if="template && !template.is_active" color="grey-3" text-color="grey-7"
                label="inactif" class="q-ml-sm" />
              <q-badge v-if="dirty" color="amber-1" text-color="amber-9"
                label="non sauvegardé" class="q-ml-sm" />
            </div>
          </div>
          <q-btn flat round dense icon="close" @click="onClose" />
        </div>
      </q-card-section>

      <q-separator />

      <q-card-section v-if="loading" class="flex flex-center q-pa-xl">
        <q-spinner size="40px" color="primary" />
      </q-card-section>

      <q-card-section v-else-if="error" class="text-negative q-pa-md">
        <q-icon name="error" size="20px" class="q-mr-sm" />{{ error }}
      </q-card-section>

      <!-- Body: meta grid + flow tree -->
      <q-card-section v-else-if="template" class="col fe-body">
        <div class="fe-body-grid">
          <!-- Left: metadata form -->
          <div class="fe-meta-col">
            <div class="text-caption text-weight-bold text-grey-7 q-mb-sm">Informations</div>

            <q-input v-model="template.template_name" dense outlined stack-label label="Nom du template *"
              :disable="template.is_system" @update:model-value="markDirty" />

            <div class="row q-col-gutter-sm q-mt-xs">
              <div class="col-6">
                <q-select v-model="template.category" dense outlined stack-label label="Catégorie"
                  emit-value map-options :options="CATEGORY_OPTIONS"
                  @update:model-value="markDirty" />
              </div>
              <div class="col-6">
                <q-select v-model="template.applies_to" dense outlined stack-label label="Applique à"
                  emit-value map-options :options="APPLIES_TO_OPTIONS" clearable
                  @update:model-value="markDirty" />
              </div>
            </div>

            <q-input v-model="template.icon" dense outlined stack-label label="Icône (material)"
              placeholder="account_tree" class="q-mt-xs"
              @update:model-value="markDirty">
              <template #prepend><q-icon :name="template.icon || 'account_tree'" /></template>
            </q-input>

            <q-select v-model="template.trigger_event" dense outlined stack-label label="Événement déclencheur"
              emit-value map-options :options="TRIGGER_EVENT_OPTIONS" clearable
              hint="Quand ce flow doit-il démarrer automatiquement ?"
              class="q-mt-xs" @update:model-value="markDirty" />

            <!-- Trigger condition — JSONLogic (or simple expression). -->
            <div class="q-mt-xs">
              <div class="row items-center q-mb-xs">
                <div class="text-caption text-weight-medium text-grey-8">Condition de démarrage</div>
                <q-space />
                <VariablePicker :applies-to="template.applies_to"
                  @insert="onInsertCondition" />
              </div>
              <q-input v-model="template.trigger_condition" dense outlined autogrow
                :placeholder="conditionPlaceholder"
                @update:model-value="markDirty" />
              <div class="text-caption text-grey-6 q-mt-xs">
                Facultatif. Filtre <b>au moment</b> où l'événement
                « {{ triggerEventLabel }} » arrive : le flow démarre seulement si
                la condition est vraie. <b>Ce n'est pas un scheduler</b> — pour
                « X jours après / à une date », utilisez une étape
                <code>wait</code> dans le flow.
              </div>

              <q-expansion-item dense expand-separator icon="lightbulb"
                label="Exemples selon le contexte" class="q-mt-xs condition-help">
                <q-card flat class="q-mt-xs">
                  <q-card-section class="q-pa-sm text-caption text-grey-8">
                    <div v-if="conditionExamples.length">
                      <div v-for="(ex, i) in conditionExamples" :key="i" class="q-mb-sm example-row">
                        <div class="text-weight-medium text-grey-9">{{ ex.title }}</div>
                        <div class="text-grey-7 q-mb-xs">{{ ex.desc }}</div>
                        <div class="row items-start no-wrap">
                          <div class="condition-code col">{{ ex.code }}</div>
                          <q-btn flat dense size="xs" icon="north_east" color="primary"
                            class="q-ml-xs" @click="useExample(ex.code)">
                            <q-tooltip>Utiliser cet exemple</q-tooltip>
                          </q-btn>
                        </div>
                      </div>
                    </div>
                    <div v-else class="text-grey-7">
                      Choisissez un « Applique à » ci-dessus pour voir des exemples adaptés.
                    </div>

                    <q-separator class="q-my-sm" />

                    <div class="text-caption text-grey-7">
                      <b>Format long (JSONLogic)</b> pour conditions complexes :
                      <div v-pre class="condition-code">{"and": [{"==": [{"var": "customer.customer_type"}, "Individual"]}, {">=": [{"var": "contract.monthly_price"}, 100]}]}</div>
                      <div class="q-mt-xs"><b>Format court</b> pour cas simples :
                      <div v-pre class="condition-code">customer.customer_type == "Individual"</div>
                      </div>
                    </div>
                  </q-card-section>
                </q-card>
              </q-expansion-item>
            </div>

            <q-input v-model="template.description" dense outlined stack-label type="textarea"
              :rows="2" label="Description" class="q-mt-xs"
              @update:model-value="markDirty" />

            <q-input v-model="template.tags" dense outlined stack-label label="Tags (séparés par ,)"
              class="q-mt-xs" @update:model-value="markDirty" />

            <div class="q-mt-sm">
              <q-toggle v-model="active" label="Actif" color="green-6"
                @update:model-value="onToggleActive" />
            </div>

            <q-input v-model="template.notes" dense outlined stack-label type="textarea"
              :rows="3" label="Notes internes" class="q-mt-md"
              @update:model-value="markDirty" />
          </div>

          <!-- Right: flow tree -->
          <div class="fe-tree-col">
            <div class="row items-center q-mb-sm">
              <div class="text-caption text-weight-bold text-grey-7">Étapes du flow</div>
              <q-space />
              <q-badge v-if="stepCount" color="green-1" text-color="green-8" :label="`${stepCount} étape${stepCount > 1 ? 's' : ''}`" />
            </div>
            <FlowEditor :model-value="template.flow_definition"
              :kind-catalog="PROJECT_KINDS"
              :applies-to="template.applies_to"
              @update:model-value="onDefChange" />
          </div>
        </div>
      </q-card-section>

      <q-separator />

      <!-- Footer actions -->
      <q-card-actions class="fe-footer">
        <q-btn v-if="mode === 'edit' && !template?.is_system"
          flat color="negative" icon="delete" label="Supprimer" no-caps
          @click="onDelete" />
        <q-btn v-if="mode === 'edit'"
          flat color="primary" icon="content_copy" label="Dupliquer" no-caps
          @click="onDuplicate" />
        <q-space />
        <q-btn flat color="grey-7" label="Fermer" no-caps @click="onClose" />
        <q-btn unelevated color="primary" icon="save"
          :label="mode === 'new' ? 'Créer' : 'Enregistrer'" no-caps
          :loading="saving" :disable="!canSave"
          @click="onSave" />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { Notify } from 'quasar'
import { useFlowEditor } from 'src/composables/useFlowEditor'
import FlowEditor from './FlowEditor.vue'
import VariablePicker from './VariablePicker.vue'
import { PROJECT_KINDS } from './kind-catalogs'

// ── Static option sets (defined once; never recomputed) ────────────────────
const CATEGORY_OPTIONS = [
  { label: 'Résidentiel',  value: 'residential' },
  { label: 'Commercial',   value: 'commercial' },
  { label: 'Dépannage',    value: 'incident' },
  { label: 'Administratif',value: 'admin' },
  { label: 'Agent AI',     value: 'agent' },
  { label: 'Autre',        value: 'other' },
]

const APPLIES_TO_OPTIONS = [
  { label: 'Devis (Quotation)',       value: 'Quotation' },
  { label: 'Contrat (Service Contract)', value: 'Service Contract' },
  { label: 'Ticket (Issue)',          value: 'Issue' },
  { label: 'Client (Customer)',       value: 'Customer' },
  { label: 'Abonnement (Subscription)', value: 'Subscription' },
]

// Must match Flow Template DocType select options exactly — values are
// validated server-side. If you add a new one, also extend the DocType.
const TRIGGER_EVENT_OPTIONS = [
  { label: 'Contrat signé',              value: 'on_contract_signed' },
  { label: 'Paiement reçu',              value: 'on_payment_received' },
  { label: 'Abonnement actif',           value: 'on_subscription_active' },
  { label: 'Devis créé',                 value: 'on_quotation_created' },
  { label: 'Devis accepté',              value: 'on_quotation_accepted' },
  { label: 'Ticket ouvert',              value: 'on_issue_opened' },
  { label: 'Client créé',                value: 'on_customer_created' },
  { label: 'Intervention terminée',      value: 'on_dispatch_completed' },
  { label: 'Manuel (bouton)',            value: 'manual' },
]

// Domain-specific example conditions. Built per applies_to so the examples
// reference the right variable paths and real business cases.
const CONDITION_EXAMPLES = {
  Customer: [
    { title: 'Particulier uniquement',     desc: 'Filtre pour les clients résidentiels',
      code: '{"==": [{"var": "customer.customer_type"}, "Individual"]}' },
    { title: 'Entreprise uniquement',       desc: 'Filtre pour les clients commerciaux',
      code: '{"==": [{"var": "customer.customer_type"}, "Company"]}' },
    { title: 'Clients francophones',        desc: 'Routage par langue',
      code: '{"==": [{"var": "customer.language"}, "fr"]}' },
    { title: 'Zone Montréal',               desc: 'Routage géographique',
      code: '{"==": [{"var": "customer.territory"}, "Montréal"]}' },
  ],
  Quotation: [
    { title: 'Devis > 500 $',                desc: 'Seulement pour les gros devis',
      code: '{">": [{"var": "quotation.grand_total"}, 500]}' },
    { title: 'Devis résidentiel',            desc: 'Filtre par type de client',
      code: '{"==": [{"var": "customer.customer_type"}, "Individual"]}' },
  ],
  'Service Contract': [
    { title: 'Contrats haut de gamme',       desc: 'Onboarding VIP pour ≥ 100 $/mois',
      code: '{">=": [{"var": "contract.monthly_price"}, 100]}' },
    { title: 'Plan Gigabit seulement',       desc: 'Routage par plan',
      code: '{"==": [{"var": "contract.plan"}, "GIGA-1000"]}' },
    { title: 'Contrats résidentiels',        desc: 'Filtre par type de client',
      code: '{"==": [{"var": "customer.customer_type"}, "Individual"]}' },
  ],
  Issue: [
    { title: 'Tickets urgents',              desc: 'Escalade immédiate',
      code: '{"==": [{"var": "issue.priority"}, "Urgent"]}' },
    { title: 'Incidents techniques',          desc: 'Filtre par type',
      code: '{"==": [{"var": "issue.issue_type"}, "Incident"]}' },
    { title: 'Tickets haute priorité',       desc: 'Urgent ou High',
      code: '{"in": [{"var": "issue.priority"}, ["Urgent", "High"]]}' },
  ],
  Subscription: [
    { title: 'Abonnements actifs',           desc: 'Filtre sur le statut',
      code: '{"==": [{"var": "subscription.status"}, "Active"]}' },
  ],
}

// ── Composable state ────────────────────────────────────────────────────────
const fe = useFlowEditor()
const {
  isOpen, template, templateName, mode, loading, saving, error, dirty,
  markDirty, close, save, duplicate, remove,
} = fe

// Local proxy for the active toggle (coerces 0/1 ↔ boolean)
const active = ref(true)
watch(() => template.value?.is_active, (v) => { active.value = v === undefined ? true : !!v })

function onToggleActive (v) {
  if (template.value) {
    template.value.is_active = v ? 1 : 0
    markDirty()
  }
}

/** Replace the flow_definition when the tree editor emits. */
function onDefChange (newDef) {
  if (!template.value) return
  template.value.flow_definition = newDef
  markDirty()
}

/**
 * Append a picked variable at the end of the trigger_condition field.
 * We don't try to insert at the cursor position — the extra plumbing
 * (textarea ref + selection range) isn't worth it for a field this small.
 * Users can always reposition manually.
 */
function onInsertCondition (text) {
  if (!template.value) return
  const cur = template.value.trigger_condition || ''
  template.value.trigger_condition = cur + text
  markDirty()
}

/** Replace the whole condition with an example — clearer than appending. */
function useExample (code) {
  if (!template.value) return
  template.value.trigger_condition = code
  markDirty()
}

/** Contextual examples based on applies_to (empty list falls back to a hint). */
const conditionExamples = computed(() => {
  const a = template.value?.applies_to
  return CONDITION_EXAMPLES[a] || []
})

/** Placeholder adapted to the chosen applies_to (first example of that domain). */
const conditionPlaceholder = computed(() => {
  const ex = conditionExamples.value[0]
  return ex?.code || '{"==": [{"var": "customer.customer_type"}, "Individual"]}'
})

/** Human label of the currently picked trigger_event for the hint text. */
const triggerEventLabel = computed(() => {
  const e = template.value?.trigger_event
  if (!e) return 'l\'événement choisi'
  return TRIGGER_EVENT_OPTIONS.find(o => o.value === e)?.label || e
})

/** Number of steps in the current def (memoised by Vue). */
const stepCount = computed(() => template.value?.flow_definition?.steps?.length || 0)

/** Gate the Save button. */
const canSave = computed(() => {
  if (saving.value) return false
  if (!template.value?.template_name?.trim()) return false
  if (mode.value === 'edit' && !dirty.value) return false
  return true
})

// ── Actions ─────────────────────────────────────────────────────────────────

async function onSave () {
  try {
    await save()
    Notify.create({ type: 'positive', message: 'Template sauvegardé', timeout: 1500 })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message, timeout: 3000 })
  }
}

async function onDuplicate () {
  try {
    await duplicate()
    Notify.create({ type: 'positive', message: 'Template dupliqué (copie inactive)', timeout: 2000 })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message, timeout: 3000 })
  }
}

async function onDelete () {
  if (!window.confirm(`Supprimer le template "${template.value?.template_name}" ?`)) return
  try {
    await remove()
    Notify.create({ type: 'info', message: 'Template supprimé', timeout: 1500 })
  } catch (e) {
    Notify.create({ type: 'negative', message: 'Erreur: ' + e.message, timeout: 3000 })
  }
}

function onClose () { close() }

function onModelUpdate (v) { if (!v) close() }
</script>

<style scoped>
.flow-editor-dialog {
  width: 100vw;
  height: 100vh;
  max-width: 100vw;
  max-height: 100vh;
  background: #f8fafc;
}
.fe-header { padding: 10px 16px; background: #fff; }
.fe-body   { overflow-y: auto; padding: 16px; }
.fe-footer { padding: 10px 16px; background: #fff; }

.fe-body-grid {
  display: grid;
  grid-template-columns: minmax(260px, 340px) 1fr;
  gap: 20px;
  align-items: start;
}

@media (max-width: 700px) {
  .fe-body-grid { grid-template-columns: 1fr; }
}

.fe-meta-col, .fe-tree-col {
  background: #fff;
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  padding: 12px;
}

/* Condition helper: compact code snippets so the examples don't wrap awkwardly. */
.condition-help :deep(.q-item) { min-height: 32px; padding: 6px 8px; }
.condition-code {
  background: #f1f5f9;
  color: #1e293b;
  padding: 4px 8px;
  border-radius: 4px;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  margin-top: 3px;
  word-break: break-all;
}
.example-row { padding: 6px 0; border-bottom: 1px solid #f1f5f9; }
.example-row:last-child { border-bottom: none; }
</style>
