/**
 * GIS export modal controller.
 *
 *   openExportGisModal({ title, kind, parcelFeatures, zoneFeatures,
 *                        otherByLayer, clipGeometry })
 *
 * Opens the modal seeded with:
 *   - a default filename ('area_analysis' / 'circle_analysis'),
 *   - the union of all source-attribute keys across the intersecting
 *     features, each pre-filled with its own name in the rename column.
 *
 * On Export: gathers the renamed map and calls exportFeaturesToGis().
 *
 * Symmetric to src/import-modal.js — same Bootstrap modal pattern.
 */

import { Modal } from 'bootstrap';
import { exportFeaturesToGis } from './gis-export.js';

const els = {};
let modal = null;
let state = null;

function cacheEls() {
  if (els.root) return;
  els.root     = document.getElementById('exportGisModal');
  els.summary  = document.getElementById('export-gis-summary');
  els.filename = document.getElementById('export-gis-filename');
  els.tbody    = document.getElementById('export-gis-fields-tbody');
  els.fmtHint  = document.getElementById('export-gis-format-hint');
  els.btnGo    = document.getElementById('export-gis-go');
  els.fmtInputs = Array.from(document.querySelectorAll('input[name="export-gis-format"]'));

  // Wire format-change handler so the SHP warning + filename suggestion react.
  if (!els.root.dataset.wired) {
    els.root.dataset.wired = '1';
    els.fmtInputs.forEach((r) => r.addEventListener('change', onFormatChange));
    els.btnGo.addEventListener('click', onExportClick);
  }
}

// ---------------------------------------------------------------------------
// State helpers
// ---------------------------------------------------------------------------

function collectFeatures(ctx) {
  const out = [];
  for (const f of ctx.parcelFeatures || []) out.push(tagWithSource(f, 'Parcels'));
  for (const f of ctx.zoneFeatures   || []) out.push(tagWithSource(f, 'Zones'));
  for (const [layerTitle, arr] of Object.entries(ctx.otherByLayer || {})) {
    for (const f of arr) out.push(tagWithSource(f, layerTitle));
  }
  return out;
}

/**
 * Add a `_source` property to a cloned feature so the export carries layer
 * provenance. We clone so the source feature is never mutated.
 */
function tagWithSource(feature, sourceLabel) {
  const clone = feature.clone();
  clone.set('_source', sourceLabel);
  return clone;
}

/** Union of source-attribute keys across all features (skipping internals). */
function unionAttributeKeys(features) {
  const skip = new Set(['geometry', '_layerType']);
  const seen = new Map();
  for (const f of features) {
    for (const k of Object.keys(f.getProperties() || {})) {
      if (skip.has(k)) continue;
      if (!seen.has(k)) seen.set(k, true);
    }
  }
  // Ensure _source is always last so it shows up at the bottom of the table.
  seen.delete('_source');
  const keys = Array.from(seen.keys());
  keys.push('_source');
  return keys;
}

// ---------------------------------------------------------------------------
// Rendering
// ---------------------------------------------------------------------------

function renderFieldsTable() {
  const fmt = currentFormat();
  els.tbody.innerHTML = state.keys.map((src) => {
    const current = state.rename[src] ?? src;
    const overLen = fmt === 'shp' && current.length > 10;
    const warn = overLen
      ? `<div class="form-text text-danger mt-1">
           ${escapeHtml(current.length)} characters — Shapefile will
           truncate / rename.
         </div>`
      : '';
    return `
      <tr>
        <td><code>${escapeHtml(src)}</code></td>
        <td>
          <input type="text" class="form-control form-control-sm export-field-rename"
                 data-src="${escapeAttr(src)}"
                 value="${escapeAttr(current)}">
          ${warn}
        </td>
      </tr>
    `;
  }).join('');
  els.tbody.querySelectorAll('.export-field-rename').forEach((inp) => {
    inp.addEventListener('input', (e) => {
      const src = e.target.dataset.src;
      state.rename[src] = e.target.value;
      // Re-render only when SHP is active so the over-length warning toggles.
      if (currentFormat() === 'shp') renderFieldsTable();
    });
  });
}

function onFormatChange() {
  const fmt = currentFormat();
  els.fmtHint.innerHTML = {
    geojson: 'GeoJSON keeps all attributes as-is and is the safest default.',
    shp:     'Shapefile attribute names are limited to <strong>10 characters</strong> ' +
             'and alphanumeric/underscore only. Over-length names will be truncated ' +
             '(collisions are auto-numbered). One file per geometry type is written, ' +
             'all zipped into one download.',
    kml:     'KML preserves attribute names; the first non-empty renamed field is used ' +
             'as each feature\'s <name> in Google Earth.',
  }[fmt];
  renderFieldsTable();
}

function currentFormat() {
  return els.fmtInputs.find((r) => r.checked)?.value || 'geojson';
}

// ---------------------------------------------------------------------------
// Export action
// ---------------------------------------------------------------------------

async function onExportClick() {
  const format = currentFormat();
  const filenameBase = (els.filename.value || 'export').replace(/[^A-Za-z0-9_\-]+/g, '_');

  els.btnGo.disabled = true;
  try {
    await exportFeaturesToGis({
      features: state.features,
      rename: state.rename,
      format,
      filenameBase,
    });
    modal.hide();
  } catch (err) {
    console.error('[ExportGIS] failed:', err);
    alert('Export failed: ' + err.message);
  } finally {
    els.btnGo.disabled = false;
  }
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

export function openExportGisModal(ctx) {
  cacheEls();
  if (!els.root) {
    console.warn('[ExportGIS] Modal missing from DOM');
    return;
  }

  const features = collectFeatures(ctx);
  if (features.length === 0) {
    alert('No intersecting features to export.');
    return;
  }
  const keys = unionAttributeKeys(features);
  const rename = Object.fromEntries(keys.map((k) => [k, k]));

  state = { features, keys, rename };
  els.summary.textContent =
    `${features.length} feature${features.length === 1 ? '' : 's'} ` +
    `intersecting the ${ctx.kind === 'circle' ? 'circle' : 'area'}`;
  els.filename.value = (ctx.kind === 'circle' ? 'circle_analysis' : 'area_analysis');

  // Reset format to GeoJSON default and render.
  const def = document.getElementById('export-gis-fmt-geojson');
  if (def) def.checked = true;
  onFormatChange();

  modal = Modal.getOrCreateInstance(els.root);
  modal.show();
}

// ---------------------------------------------------------------------------
// HTML-escape helpers
// ---------------------------------------------------------------------------

function escapeHtml(s) {
  return String(s)
    .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}
function escapeAttr(s) { return escapeHtml(s); }
