<template>
  <v-card>
    <v-card-title>Legacy migration</v-card-title>
    <v-card-text>
      <p class="text-body-2 mb-3">
        Migrate existing ImageRepo and GallerySubscriber data into FabledCurator.
        Each app produces a JSON export file via a small script in its own repo
        (<code>scripts/export_for_fabledcurator.py</code>); upload both files
        here and run the steps in order.
      </p>

      <ol class="text-body-2 mb-3 fc-migrate__hints">
        <li>Backup FC (creates a pre-migration snapshot).</li>
        <li>Upload + ingest GS export.</li>
        <li>Upload + ingest IR export.</li>
        <li>Switch to <strong>Import tab</strong> → trigger the existing FC filesystem scan over the bind-mounted IR images dir.</li>
        <li>Return here → apply IR tag associations (joins by sha256).</li>
        <li>Queue ML re-processing.</li>
        <li>Verify.</li>
      </ol>

      <div class="fc-migrate__uploads">
        <v-file-input
          v-model="gsFile"
          label="GallerySubscriber export (gs-export.json)"
          accept="application/json,.json"
          density="compact"
          show-size
          prepend-icon="mdi-upload"
        />
        <v-file-input
          v-model="irFile"
          label="ImageRepo export (ir-export.json)"
          accept="application/json,.json"
          density="compact"
          show-size
          prepend-icon="mdi-upload"
        />
      </div>

      <div class="fc-migrate__steps mt-3">
        <v-btn
          color="accent" variant="tonal" prepend-icon="mdi-content-save"
          :disabled="store.isRunning"
          @click="onBackup"
        >1. Backup FC</v-btn>
        <v-btn
          color="primary" variant="tonal" prepend-icon="mdi-database-arrow-right"
          :disabled="store.isRunning || !gsFile"
          @click="onIngestGs"
        >2. Ingest GS</v-btn>
        <v-btn
          color="primary" variant="tonal" prepend-icon="mdi-database-arrow-right"
          :disabled="store.isRunning || !irFile"
          @click="onIngestIr"
        >3. Ingest IR</v-btn>
        <v-btn
          color="primary" variant="tonal" prepend-icon="mdi-tag-multiple"
          :disabled="store.isRunning"
          @click="onTagApply"
        >5. Apply IR tags</v-btn>
        <v-btn
          variant="outlined" prepend-icon="mdi-brain"
          :disabled="store.isRunning"
          @click="onMlQueue"
        >6. Queue ML</v-btn>
        <v-btn
          variant="outlined" prepend-icon="mdi-check-circle"
          :disabled="store.isRunning"
          @click="onVerify"
        >7. Verify</v-btn>
      </div>

      <v-btn
        color="error" variant="outlined" prepend-icon="mdi-restore" class="mt-3"
        :disabled="store.isRunning"
        @click="onRollback"
      >Rollback to pre-migration backup</v-btn>

      <v-alert v-if="store.error" type="error" variant="tonal" class="mt-3" closable>
        {{ String(store.error) }}
      </v-alert>

      <v-card v-if="store.activeRun" variant="outlined" class="mt-4">
        <v-card-text>
          <div class="text-subtitle-2">
            #{{ store.activeRun.id }} — {{ store.activeRun.kind }}
            ({{ store.activeRun.status }})
          </div>
          <v-progress-linear
            v-if="store.isRunning" indeterminate color="accent" class="my-2"
          />
          <div class="text-caption">
            Rows: {{ store.activeRun.counts.rows_processed || 0 }} processed,
            {{ store.activeRun.counts.rows_inserted || 0 }} inserted,
            {{ store.activeRun.counts.rows_skipped || 0 }} skipped.
            Conflicts: {{ store.activeRun.counts.conflicts || 0 }}.
          </div>
          <div v-if="store.activeRun.error" class="text-error mt-1">
            {{ store.activeRun.error }}
          </div>
        </v-card-text>
      </v-card>

      <div v-if="store.recentRuns.length" class="mt-4">
        <div class="text-subtitle-2 mb-2">Recent runs</div>
        <ul class="fc-migrate__history">
          <li v-for="r in store.recentRuns" :key="r.id">
            #{{ r.id }} {{ r.kind }}
            <v-chip
              size="x-small"
              :color="r.status === 'ok' ? 'success' : (r.status === 'error' ? 'error' : undefined)"
            >{{ r.status }}</v-chip>
            <span class="text-caption fc-migrate__when">{{ r.started_at }}</span>
          </li>
        </ul>
      </div>
    </v-card-text>

    <v-dialog v-model="confirmOpen" max-width="520">
      <v-card>
        <v-card-title>Confirm {{ pendingLabel }}</v-card-title>
        <v-card-text>
          This will modify FC's database. Make sure you've taken a backup first.
          Continue?
        </v-card-text>
        <v-card-actions>
          <v-spacer />
          <v-btn variant="text" @click="confirmOpen = false">Cancel</v-btn>
          <v-btn color="primary" variant="tonal" @click="onConfirm">Continue</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-card>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import { useMigrationStore } from '../../stores/migration.js'

const store = useMigrationStore()

const gsFile = ref(null)
const irFile = ref(null)

const confirmOpen = ref(false)
const pendingLabel = ref('')
const pendingAction = ref(null)

onMounted(async () => {
  await store.loadRecent()
})

function _pick(model) {
  if (!model) return null
  // v-file-input v-model can be a single File or a [File] depending on Vuetify version.
  return Array.isArray(model) ? model[0] : model
}

function requestConfirm(label, action) {
  pendingLabel.value = label
  pendingAction.value = action
  confirmOpen.value = true
}

async function onConfirm() {
  confirmOpen.value = false
  const action = pendingAction.value
  pendingAction.value = null
  if (action) await action()
}

async function onBackup() {
  await store.trigger('backup', { tag: 'pre_migration' })
}

async function onIngestGs() {
  const file = _pick(gsFile.value)
  if (!file) return
  requestConfirm('Ingest GS', async () => {
    await store.trigger('gs_ingest', { dry_run: false }, file)
  })
}

async function onIngestIr() {
  const file = _pick(irFile.value)
  if (!file) return
  requestConfirm('Ingest IR', async () => {
    await store.trigger('ir_ingest', { dry_run: false }, file)
  })
}

async function onTagApply() {
  requestConfirm('Apply IR tag associations', async () => {
    await store.trigger('tag_apply', { dry_run: false })
  })
}

async function onMlQueue() {
  await store.trigger('ml_queue', {})
}

async function onVerify() {
  await store.trigger('verify', {})
}

async function onRollback() {
  requestConfirm('Rollback to pre-migration backup', async () => {
    await store.trigger('rollback', {})
  })
}
</script>

<style scoped>
.fc-migrate__hints {
  padding-left: 1.2rem;
  color: rgb(var(--v-theme-on-surface-variant));
}
.fc-migrate__uploads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.fc-migrate__steps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.fc-migrate__history {
  list-style: none;
  padding: 0;
  margin: 0;
}
.fc-migrate__history li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  border-bottom: 1px solid rgb(var(--v-theme-on-surface-variant), 0.15);
}
.fc-migrate__when {
  color: rgb(var(--v-theme-on-surface-variant));
  margin-left: auto;
}
</style>
