<script setup>
import AppLayout from '@/Layouts/AppLayout.vue';
import { ref, watch, computed, onMounted } from 'vue';
import { useForm, router } from '@inertiajs/vue3';
import Multiselect from 'vue-multiselect';
import axios from 'axios';

const props = defineProps({
  templates: Array,
  clients: Array,
});

const hasHeader = ref(true);
const detected = ref({ columns: [], delimiter: ',', has_header: true });
const importId = ref(null);
const templateApplied = ref(false);
const processing = ref(false);
const processResult = ref(null);
const mappingRows = ref([]);
const mappingSaved = ref(false);
const mappingSavedCount = ref(0);
const selectedMappingsCount = computed(() => mappingRows.value.filter(r => !r.skip && r.entity && r.field).length);
const mappingError = ref('');
const savingMappings = ref(false);

// Dynamic entity definitions and suggestions from API
const entityDefs = ref([]);
const entityOptions = computed(() => entityDefs.value.map(e => ({ value: e.key, label: e.label || e.key })));
const fieldOptionsByEntity = computed(() => Object.fromEntries(entityDefs.value.map(e => [e.key, (e.fields || []).map(f => ({ value: f, label: f }))])));
const canonicalRootByKey = computed(() => Object.fromEntries(entityDefs.value.map(e => [e.key, e.canonical_root || e.key])));
const keyByCanonicalRoot = computed(() => {
  const m = {};
  for (const e of entityDefs.value) {
    if (e.canonical_root) {
      m[e.canonical_root] = e.key;
    }
  }
  return m;
});
const suggestions = ref({});
async function loadEntityDefs() {
  try {
    const { data } = await axios.get('/api/import-entities');
    entityDefs.value = data?.entities || [];
  } catch (e) {
    console.error('Failed to load import entity definitions', e);
  }
}
async function refreshSuggestions(columns) {
  const cols = Array.isArray(columns) ? columns : (detected.value.columns || []);
  if (!cols || cols.length === 0) { return; }
  try {
    const { data } = await axios.post('/api/import-entities/suggest', { columns: cols });
    suggestions.value = { ...suggestions.value, ...(data?.suggestions || {}) };
  } catch (e) {
    console.error('Failed to load suggestions', e);
  }
}

function applySuggestionToRow(row) {
  const s = suggestions.value[row.source_column];
  if (!s) return false;
  if (!fieldOptionsByEntity.value[s.entity]) return false;
  row.entity = s.entity;
  row.field = s.field;
  // default transform on if missing
  if (!row.transform) { row.transform = 'trim'; }
  if (!row.apply_mode) { row.apply_mode = 'both'; }
  row.skip = false;
  return true;
}

const form = useForm({
  client_uuid: null,
  import_template_id: null,
  source_type: null,
  sheet_name: null,
  has_header: true,
  file: null,
});

// Bridge Multiselect (expects option objects) to our form (stores client_uuid as string)
const selectedClientOption = computed({
  get() {
    const cuuid = form.client_uuid;
    if (!cuuid) return null;
    return (props.clients || []).find(c => c.uuid === cuuid) || null;
  },
  set(val) {
    form.client_uuid = val ? val.uuid : null;
  }
});

// Bridge Template Multiselect to store only template id (number) in form
const selectedTemplateOption = computed({
  get() {
    const tid = form.import_template_id;
    if (tid == null) return null;
    return (props.templates || []).find(t => t.id === tid) || null;
  },
  set(val) {
    form.import_template_id = val ? val.id : null;
  }
});

// Helper: selected client's numeric id (fallback)
const selectedClientId = computed(() => {
  const cuuid = form.client_uuid;
  if (!cuuid) return null;
  const c = (props.clients || []).find(x => x.uuid === cuuid);
  return c ? c.id : null;
});

// Show only global templates when no client is selected.
// When a client is selected, show only that client's templates (match by client_uuid).
const filteredTemplates = computed(() => {
  const cuuid = form.client_uuid;
  const list = props.templates || [];
  if (!cuuid) {
    return list.filter(t => t.client_id == null);
  }
  // When client is selected, only show that client's templates (no globals)
  return list.filter(t => t.client_uuid && t.client_uuid === cuuid);
});

function onFileChange(e) {
  const files = e.target.files;
  if (files && files.length) {
    form.file = files[0];
  }
}

async function submitUpload() {
  await form.post(route('imports.store'), {
    forceFormData: true,
    onSuccess: (res) => {
      const data = res?.props || {};
    },
    onFinish: async () => {
      // After upload, fetch columns for preview
      if (!form.recentlySuccessful) return;
      // Inertia doesn't expose JSON response directly with useForm; fallback to API call using fetch
      const fd = new FormData();
      fd.append('file', form.file);
    },
  });
}

async function fetchColumns() {
  if (!importId.value) return;
  const url = route('imports.columns', { import: importId.value });
  const { data } = await axios.get(url, { params: { has_header: hasHeader.value ? 1 : 0 } });
  detected.value = {
    columns: data.columns || [],
    delimiter: data.detected_delimiter || ',',
    has_header: !!data.has_header,
  };
  // initialize simple mapping rows with defaults if none exist
  if (!mappingRows.value.length) {
    mappingRows.value = (detected.value.columns || []).map((c, idx) => ({
      source_column: c,
      entity: '',
      field: '',
      skip: false,
      transform: 'trim',
      apply_mode: 'both',
      position: idx,
    }));
  }
  await refreshSuggestions(detected.value.columns);
  // If there are mappings already (template applied or saved), load them to auto-assign
  await loadImportMappings();
}

async function uploadAndPreview() {
  if (!form.file) {
    // Basic guard: require a file before proceeding
    return;
  }
  templateApplied.value = false;
  processResult.value = null;
  const fd = new window.FormData();
  fd.append('file', form.file);
  if (form.import_template_id !== null && form.import_template_id !== undefined && String(form.import_template_id).trim() !== '') {
    fd.append('import_template_id', String(form.import_template_id));
  }
  if (form.client_uuid) {
    fd.append('client_uuid', String(form.client_uuid));
  }
  fd.append('has_header', hasHeader.value ? '1' : '0');
  try {
    const { data } = await axios.post(route('imports.store'), fd, {
      headers: { Accept: 'application/json' },
      withCredentials: true,
    });
    // Redirect immediately to the continue page for this import
    if (data?.uuid) {
      router.visit(route('imports.continue', { import: data.uuid }));
    } else if (data?.id) {
      // Fallback: if uuid not returned for some reason, fetch columns here (legacy)
      importId.value = data.id;
      await fetchColumns();
    }
  } catch (e) {
    if (e.response) {
      console.error('Upload error', e.response.status, e.response.data);
      if (e.response.data?.errors) {
        // Optionally you could surface errors in the UI; for now, log for visibility
      }
    } else {
      console.error('Upload error', e);
    }
  }
}

// If continuing an existing import, set importId and hydrate columns and mappings
// No continuation logic on Create page anymore

async function applyTemplateToImport() {
  if (!importId.value || !form.import_template_id) return;
  try {
    await axios.post(route('importTemplates.apply', { template: form.import_template_id, import: importId.value }), {}, {
      headers: { Accept: 'application/json' },
      withCredentials: true,
    });
    templateApplied.value = true;
    // Load mappings and auto-assign UI rows
    await loadImportMappings();
  } catch (e) {
    templateApplied.value = false;
    if (e.response) {
      console.error('Apply template error', e.response.status, e.response.data);
    } else {
      console.error('Apply template error', e);
    }
  }
}

async function loadImportMappings() {
  if (!importId.value) return;
  try {
    const { data } = await axios.get(route('imports.mappings.get', { import: importId.value }), {
      headers: { Accept: 'application/json' },
      withCredentials: true,
    });
    const rows = Array.isArray(data?.mappings) ? data.mappings : [];
    if (!rows.length) return;
    // Build a lookup by source_column
    const bySource = new Map(rows.map(r => [r.source_column, r]));
    // Update mappingRows (detected columns) to reflect applied mappings
    mappingRows.value = (mappingRows.value || []).map((r, idx) => {
      const m = bySource.get(r.source_column);
      if (!m) return r;
  // Parse target_field like 'person.first_name' into UI entity/field
  const [record, field] = String(m.target_field || '').split('.', 2);
  const entity = keyByCanonicalRoot.value[record] || record;
      return {
        ...r,
        entity,
        field: field || '',
        transform: m.transform || '',
        apply_mode: m.apply_mode || 'both',
        skip: false,
        position: idx,
      };
    });
  } catch (e) {
    console.error('Load import mappings error', e.response?.status || '', e.response?.data || e);
  }
}

async function processImport() {
  if (!importId.value) return;
  processing.value = true;
  processResult.value = null;
  try {
    const { data } = await axios.post(route('imports.process', { import: importId.value }), {}, {
      headers: { Accept: 'application/json' },
      withCredentials: true,
    });
    processResult.value = data;
  } catch (e) {
    if (e.response) {
      console.error('Process import error', e.response.status, e.response.data);
      processResult.value = { error: e.response.data || 'Processing failed' };
    } else {
      console.error('Process import error', e);
      processResult.value = { error: 'Processing failed' };
    }
  } finally {
    processing.value = false;
  }
}

// entity options and fields are dynamic from API

async function saveMappings() {
  if (!importId.value) return;
  mappingError.value = '';
  const mappings = mappingRows.value
    .filter(r => !r.skip && r.entity && r.field)
    .map(r => ({
      source_column: r.source_column,
  target_field: `${(canonicalRootByKey.value[r.entity] || r.entity)}.${r.field}`,
      transform: r.transform || null,
      apply_mode: r.apply_mode || 'both',
      options: null,
    }));
  if (!mappings.length) {
    mappingSaved.value = false;
    mappingError.value = 'Select entity and field for at least one column (or uncheck Skip) before saving.';
    return;
  }
  try {
    savingMappings.value = true;
    const url = (typeof route === 'function')
      ? route('imports.mappings.save', { import: importId.value })
      : `/imports/${importId.value}/mappings`;
    const { data } = await axios.post(url, { mappings }, {
      headers: { 'Accept': 'application/json' },
      withCredentials: true,
    });
    mappingSaved.value = true;
    mappingSavedCount.value = Number(data?.saved || mappings.length);
    mappingError.value = '';
  } catch (e) {
    mappingSaved.value = false;
    if (e.response) {
      console.error('Save mappings error', e.response.status, e.response.data);
      alert('Failed to save mappings: ' + (e.response.data?.message || e.response.status));
    } else {
      console.error('Save mappings error', e);
      alert('Failed to save mappings. See console for details.');
    }
  } finally {
    savingMappings.value = false;
  }
}

// Reset saved flag whenever user edits mappings
watch(mappingRows, () => {
  mappingSaved.value = false;
  mappingSavedCount.value = 0;
  mappingError.value = '';
}, { deep: true });

onMounted(async () => {
  await loadEntityDefs();
});

</script>

<template>
  <AppLayout title="New Import">
    <template #header>
      <h2 class="font-semibold text-xl text-gray-800 leading-tight">New Import</h2>
    </template>
    <div class="py-6">
      <div class="max-w-5xl mx-auto sm:px-6 lg:px-8">
        <div class="bg-white shadow sm:rounded-lg p-6 space-y-6">
          <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
            <div>
              <label class="block text-sm font-medium text-gray-700">Client</label>
              <Multiselect
                v-model="selectedClientOption"
                :options="clients"
                track-by="uuid"
                label="name"
                placeholder="Search clients..."
                :searchable="true"
                :allow-empty="true"
                class="mt-1"
              />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700">Template</label>
              <Multiselect
                v-model="selectedTemplateOption"
                :options="filteredTemplates"
                track-by="id"
                label="name"
                placeholder="Search templates..."
                :searchable="true"
                :allow-empty="true"
                class="mt-1"
              >
                <template #option="{ option }">
                  <div class="flex items-center justify-between w-full">
                    <div class="flex items-center gap-2">
                      <span>{{ option.name }}</span>
                      <span class="ml-2 text-xs text-gray-500">({{ option.source_type }})</span>
                    </div>
                    <span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600">{{ option.client_id ? 'Client' : 'Global' }}</span>
                  </div>
                </template>
                <template #singleLabel="{ option }">
                  <div class="flex items-center gap-2">
                    <span>{{ option.name }}</span>
                    <span class="ml-1 text-xs text-gray-500">({{ option.source_type }})</span>
                    <span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-100 text-gray-600">{{ option.client_id ? 'Client' : 'Global' }}</span>
                  </div>
                </template>
              </Multiselect>
              <p class="text-xs text-gray-500 mt-1" v-if="!form.client_uuid">Only global templates are shown until a client is selected.</p>
            </div>
          </div>

          <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
            <div>
              <label class="block text-sm font-medium text-gray-700">File</label>
              <input type="file" @change="onFileChange" class="mt-1 block w-full" />
            </div>
            <div>
              <label class="block text-sm font-medium text-gray-700">Has header row</label>
              <input type="checkbox" v-model="hasHeader" class="mt-2" />
            </div>
          </div>

          <div class="flex gap-3">
            <button @click.prevent="uploadAndPreview" class="px-4 py-2 bg-blue-600 text-white rounded">Upload & Preview Columns</button>
            <button
              @click.prevent="applyTemplateToImport"
              :disabled="!importId || !form.import_template_id || templateApplied"
              class="px-4 py-2 bg-emerald-600 disabled:bg-gray-300 text-white rounded"
            >
              {{ templateApplied ? 'Template Applied' : 'Apply Template' }}
            </button>
            <button
              @click.prevent="saveMappings"
              :disabled="!importId || processing || savingMappings"
              class="px-4 py-2 bg-orange-600 disabled:bg-gray-300 text-white rounded flex items-center gap-2"
              title="Save ad-hoc mappings for this import"
            >
              <span v-if="savingMappings" class="inline-block h-4 w-4 border-2 border-white/70 border-t-transparent rounded-full animate-spin"></span>
              <span>Save Mappings</span>
              <span v-if="selectedMappingsCount" class="ml-1 text-xs bg-white/20 px-1.5 py-0.5 rounded">{{ selectedMappingsCount }}</span>
            </button>
            <button
              @click.prevent="processImport"
              :disabled="!importId || processing || (!templateApplied && !mappingSaved)"
              class="px-4 py-2 bg-purple-600 disabled:bg-gray-300 text-white rounded"
            >
              {{ processing ? 'Processing…' : 'Process Import' }}
            </button>
          </div>
          <div class="mt-2 text-xs text-gray-600" v-if="!importId">
            Upload a file first to enable saving mappings.
          </div>
          <div class="mt-2 text-xs text-gray-600" v-else-if="importId && !selectedMappingsCount">
            Select an Entity and Field for at least one detected column (or uncheck Skip) and then click Save Mappings.
          </div>

          <div v-if="detected.columns.length" class="pt-4">
            <div class="flex items-center justify-between mb-2">
              <h3 class="font-semibold">Detected Columns ({{ detected.has_header ? 'header' : 'positional' }})</h3>
              <button
                class="px-3 py-1.5 border rounded text-sm"
                @click.prevent="(async () => { await refreshSuggestions(detected.columns); mappingRows.forEach(r => applySuggestionToRow(r)); })()"
              >Auto map suggestions</button>
            </div>
            <div class="overflow-x-auto">
              <table class="min-w-full border bg-white">
                <thead>
                  <tr class="bg-gray-50 text-left text-xs uppercase text-gray-600">
                    <th class="p-2 border">Source column</th>
                    <th class="p-2 border">Entity</th>
                    <th class="p-2 border">Field</th>
                    <th class="p-2 border">Transform</th>
                    <th class="p-2 border">Apply mode</th>
                    <th class="p-2 border">Skip</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="(row, idx) in mappingRows" :key="idx" class="border-t">
                    <td class="p-2 border text-sm">
                      <div>{{ row.source_column }}</div>
                      <div class="text-xs mt-1" v-if="suggestions[row.source_column]">
                        <span class="text-gray-500">Suggest:</span>
                        <button class="ml-1 underline text-indigo-700 hover:text-indigo-900" @click.prevent="applySuggestionToRow(row)">
                          {{ suggestions[row.source_column].entity }}.{{ suggestions[row.source_column].field }}
                        </button>
                      </div>
                    </td>
                    <td class="p-2 border">
                      <select v-model="row.entity" class="border rounded p-1 w-full">
                        <option value="">—</option>
                        <option v-for="opt in entityOptions" :key="opt.value" :value="opt.value">{{ opt.label }}</option>
                      </select>
                    </td>
                    <td class="p-2 border">
                      <select v-model="row.field" class="border rounded p-1 w-full">
                        <option value="">—</option>
                        <option v-for="f in fieldOptionsByEntity[row.entity] || []" :key="f.value" :value="f.value">{{ f.label }}</option>
                      </select>
                    </td>
                    <td class="p-2 border">
                      <select v-model="row.transform" class="border rounded p-1 w-full">
                        <option value="">None</option>
                        <option value="trim">Trim</option>
                        <option value="upper">Uppercase</option>
                        <option value="lower">Lowercase</option>
                      </select>
                    </td>
                    <td class="p-2 border">
                      <select v-model="row.apply_mode" class="border rounded p-1 w-full">
                        <option value="both">Both</option>
                        <option value="insert">Insert only</option>
                        <option value="update">Update only</option>
                      </select>
                    </td>
                    <td class="p-2 border text-center">
                      <input type="checkbox" v-model="row.skip" />
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div v-if="mappingSaved" class="text-sm text-emerald-700 mt-2">Mappings saved ({{ mappingSavedCount }}).</div>
            <div v-else-if="mappingError" class="text-sm text-red-600 mt-2">{{ mappingError }}</div>
          </div>

          <div v-if="processResult" class="pt-4">
            <h3 class="font-semibold mb-2">Import Result</h3>
            <pre class="bg-gray-50 border rounded p-3 text-sm overflow-x-auto">{{ processResult }}</pre>
          </div>
        </div>
      </div>
    </div>
  </AppLayout>
</template>