import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import {
  Steps,
  Button,
  Space,
  Card,
  Checkbox,
  Select,
  Slider,
  InputNumber,
  Statistic,
  Alert,
  Progress,
  Tag,
  Row,
  Col,
  Typography,
  Spin,
  Result,
} from 'antd';
import {
  GlobalOutlined,
  DatabaseOutlined,
  CompassOutlined,
  CheckCircleOutlined,
  CloseCircleOutlined,
  LoadingOutlined,
  MinusCircleOutlined,
  WarningOutlined,
} from '@ant-design/icons';
import { MapContainer, TileLayer, Rectangle, Polygon, useMap } from 'react-leaflet';
import type { LatLngBoundsExpression } from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { api } from '@/lib/api';
import type {
  Cut,
  MapSettings,
  AreaImportPreviewResult,
  AreaImportProgress,
  AreaImportSourceStatus,
} from '@/types/api';
import { getErrorMessage } from '@/utils/getErrorMessage';

const { Text, Title } = Typography;

interface AreaImportWizardProps {
  cuts: Cut[];
  onComplete?: () => void;
}

const SOURCE_STATUS_ICONS: Record<AreaImportSourceStatus, React.ReactNode> = {
  pending: <MinusCircleOutlined style={{ color: '#8c8c8c' }} />,
  running: <LoadingOutlined style={{ color: '#1890ff' }} spin />,
  complete: <CheckCircleOutlined style={{ color: '#52c41a' }} />,
  failed: <CloseCircleOutlined style={{ color: '#ff4d4f' }} />,
  skipped: <MinusCircleOutlined style={{ color: '#d9d9d9' }} />,
};

const ZOOM_PRESETS = [
  { value: 15, label: 'Neighborhood (zoom 15)' },
  { value: 13, label: 'District (zoom 13)' },
  { value: 10, label: 'City-wide (zoom 10)' },
  { value: 8, label: 'Region (zoom 8)' },
];

/**
 * Client-side bounding box calculation from center + zoom + viewport.
 * Mirrors the server-side boundsFromCenterZoom() in spatial.ts.
 */
function boundsFromCenterZoom(
  lat: number,
  lng: number,
  zoom: number,
  viewportWidth = 1024,
  viewportHeight = 768,
): { minLat: number; maxLat: number; minLng: number; maxLng: number } {
  const metersPerPixel = (156543.03392 * Math.cos((lat * Math.PI) / 180)) / Math.pow(2, zoom);
  const halfWidthMeters = (viewportWidth / 2) * metersPerPixel;
  const halfHeightMeters = (viewportHeight / 2) * metersPerPixel;
  const latDelta = halfHeightMeters / 111320;
  const lngDelta = halfWidthMeters / (111320 * Math.cos((lat * Math.PI) / 180));
  return {
    minLat: lat - latDelta,
    maxLat: lat + latDelta,
    minLng: lng - lngDelta,
    maxLng: lng + lngDelta,
  };
}

/**
 * Approximate area in sq km from a bounding box.
 */
function areaSqKm(bounds: { minLat: number; maxLat: number; minLng: number; maxLng: number }): number {
  const latMeters = (bounds.maxLat - bounds.minLat) * 111320;
  const avgLat = (bounds.minLat + bounds.maxLat) / 2;
  const lngMeters = (bounds.maxLng - bounds.minLng) * 111320 * Math.cos((avgLat * Math.PI) / 180);
  return (latMeters * lngMeters) / 1_000_000;
}

/** Fit the map to given bounds whenever they change. */
function FitBoundsUpdater({ bounds }: { bounds: LatLngBoundsExpression }) {
  const map = useMap();
  useEffect(() => {
    map.fitBounds(bounds, { padding: [20, 20] });
  }, [map, bounds]);
  return null;
}

export default function AreaImportWizard({ cuts, onComplete }: AreaImportWizardProps) {
  const [currentStep, setCurrentStep] = useState(0);

  // Step 0: Define area
  const [areaType, setAreaType] = useState<'cut' | 'viewport'>('cut');
  const [selectedCutId, setSelectedCutId] = useState<string | undefined>();
  const [mapSettings, setMapSettings] = useState<MapSettings | null>(null);
  const [mapSettingsLoading, setMapSettingsLoading] = useState(false);
  const [zoomOverride, setZoomOverride] = useState<number | null>(null);

  // Step 1: Sources
  const [osmEnabled, setOsmEnabled] = useState(true);
  const [narEnabled, setNarEnabled] = useState(true);
  const [narResidentialOnly, setNarResidentialOnly] = useState(true);
  const [rgEnabled, setRgEnabled] = useState(false);
  const [rgSpacing, setRgSpacing] = useState(100);
  const [rgMaxPoints, setRgMaxPoints] = useState(500);

  // Step 2: Preview
  const [preview, setPreview] = useState<AreaImportPreviewResult | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [previewError, setPreviewError] = useState<string | null>(null);

  // Step 3: Progress
  const [progress, setProgress] = useState<AreaImportProgress | null>(null);
  const [importing, setImporting] = useState(false);
  const pollRef = useRef<ReturnType<typeof setInterval>>(undefined);

  // Effective zoom for viewport mode (override or map settings default)
  const effectiveZoom = zoomOverride ?? mapSettings?.zoom ?? 13;

  // Load map settings for viewport mode
  useEffect(() => {
    if (areaType === 'viewport' && !mapSettings) {
      setMapSettingsLoading(true);
      api.get('/map/settings')
        .then(({ data }) => setMapSettings(data))
        .catch(() => {})
        .finally(() => setMapSettingsLoading(false));
    }
  }, [areaType, mapSettings]);

  // Cleanup polling on unmount
  useEffect(() => {
    return () => {
      if (pollRef.current) clearInterval(pollRef.current);
    };
  }, []);

  // Compute viewport bounds for preview map
  const viewportBounds = useMemo(() => {
    if (areaType !== 'viewport' || !mapSettings?.latitude || !mapSettings?.longitude) return null;
    return boundsFromCenterZoom(
      Number(mapSettings.latitude),
      Number(mapSettings.longitude),
      effectiveZoom,
    );
  }, [areaType, mapSettings?.latitude, mapSettings?.longitude, effectiveZoom]);

  const viewportAreaSqKm = viewportBounds ? areaSqKm(viewportBounds) : null;

  // Parse cut polygon for preview map
  const selectedCutGeoJson = useMemo(() => {
    if (areaType !== 'cut' || !selectedCutId) return null;
    const cut = cuts.find((c) => c.id === selectedCutId);
    if (!cut?.geojson) return null;
    try {
      const parsed = JSON.parse(cut.geojson);
      // GeoJSON coordinates are [lng, lat] — Leaflet Polygon needs [lat, lng]
      if (parsed.type === 'Polygon' && parsed.coordinates) {
        return parsed.coordinates[0].map((c: number[]) => [c[1], c[0]] as [number, number]);
      }
      if (parsed.type === 'MultiPolygon' && parsed.coordinates) {
        // Just use the first polygon ring for preview
        return parsed.coordinates[0][0].map((c: number[]) => [c[1], c[0]] as [number, number]);
      }
      // If it's just an array of coordinate rings (legacy format)
      if (Array.isArray(parsed) && Array.isArray(parsed[0])) {
        return parsed[0].map((c: number[]) => [c[1], c[0]] as [number, number]);
      }
    } catch { /* ignore parse errors */ }
    return null;
  }, [areaType, selectedCutId, cuts]);

  // Cut bounds for fitBounds
  const cutPreviewBounds = useMemo((): LatLngBoundsExpression | null => {
    if (!selectedCutGeoJson || selectedCutGeoJson.length === 0) return null;
    let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
    for (const [lat, lng] of selectedCutGeoJson) {
      if (lat < minLat) minLat = lat;
      if (lat > maxLat) maxLat = lat;
      if (lng < minLng) minLng = lng;
      if (lng > maxLng) maxLng = lng;
    }
    return [[minLat, minLng], [maxLat, maxLng]];
  }, [selectedCutGeoJson]);

  const buildRequestBody = useCallback(() => {
    const sources: Record<string, unknown> = {
      osm: osmEnabled,
      nar: narEnabled ? { residentialOnly: narResidentialOnly } : false,
      reverseGeocode: rgEnabled ? { gridSpacingMeters: rgSpacing, maxPoints: rgMaxPoints } : false,
    };

    const body: Record<string, unknown> = { sources };

    if (areaType === 'cut') {
      body.areaType = 'cut';
      body.cutId = selectedCutId;
    } else {
      body.areaType = 'viewport';
      body.center = {
        lat: mapSettings?.latitude ? Number(mapSettings.latitude) : 53.5,
        lng: mapSettings?.longitude ? Number(mapSettings.longitude) : -113.5,
      };
      body.zoom = effectiveZoom;
    }

    return body;
  }, [areaType, selectedCutId, mapSettings, effectiveZoom, osmEnabled, narEnabled, narResidentialOnly, rgEnabled, rgSpacing, rgMaxPoints]);

  const fetchPreview = async () => {
    setPreviewLoading(true);
    setPreviewError(null);
    try {
      const { data } = await api.post('/map/area-import/preview', buildRequestBody());
      setPreview(data);
    } catch (err: unknown) {
      setPreviewError(getErrorMessage(err, 'Preview failed'));
    } finally {
      setPreviewLoading(false);
    }
  };

  const startImport = async () => {
    setImporting(true);
    try {
      const body = { ...buildRequestBody(), deduplicateRadius: 5, batchSize: 1000 };
      const { data } = await api.post('/map/area-import', body);
      const currentImportId = data.importId;
      setCurrentStep(3);

      // Start polling
      pollRef.current = setInterval(async () => {
        try {
          const { data: prog } = await api.get(`/map/area-import/status/${currentImportId}`);
          setProgress(prog);
          if (prog.status === 'complete' || prog.status === 'failed') {
            if (pollRef.current) clearInterval(pollRef.current);
          }
        } catch {
          // Ignore polling errors
        }
      }, 2000);
    } catch (err: unknown) {
      setPreviewError(getErrorMessage(err, 'Failed to start import'));
      setImporting(false);
    }
  };

  const canProceedStep0 = areaType === 'cut' ? !!selectedCutId : (!!mapSettings?.latitude && !!mapSettings?.longitude);
  const canProceedStep1 = osmEnabled || narEnabled || rgEnabled;

  // ─── Mini Map Preview ─────────────────────────────────────────────

  const renderPreviewMap = () => {
    // Viewport mode: show rectangle
    if (areaType === 'viewport' && viewportBounds) {
      const mapBounds: LatLngBoundsExpression = [
        [viewportBounds.minLat, viewportBounds.minLng],
        [viewportBounds.maxLat, viewportBounds.maxLng],
      ];
      return (
        <Card size="small" title="Import Area Preview" style={{ marginTop: 12 }}>
          <div style={{ height: 250 }}>
            <MapContainer
              bounds={mapBounds}
              style={{ width: '100%', height: '100%' }}
              zoomControl={false}
              dragging={false}
              scrollWheelZoom={false}
              doubleClickZoom={false}
              touchZoom={false}
              boxZoom={false}
              keyboard={false}
              attributionControl={false}
            >
              <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
              <FitBoundsUpdater bounds={mapBounds} />
              <Rectangle
                bounds={mapBounds}
                pathOptions={{
                  color: '#1890ff',
                  weight: 2,
                  dashArray: '6 4',
                  fillColor: '#1890ff',
                  fillOpacity: 0.1,
                }}
              />
            </MapContainer>
          </div>
        </Card>
      );
    }

    // Cut mode: show polygon
    if (areaType === 'cut' && selectedCutGeoJson && cutPreviewBounds) {
      return (
        <Card size="small" title="Import Area Preview" style={{ marginTop: 12 }}>
          <div style={{ height: 250 }}>
            <MapContainer
              bounds={cutPreviewBounds}
              style={{ width: '100%', height: '100%' }}
              zoomControl={false}
              dragging={false}
              scrollWheelZoom={false}
              doubleClickZoom={false}
              touchZoom={false}
              boxZoom={false}
              keyboard={false}
              attributionControl={false}
            >
              <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
              <FitBoundsUpdater bounds={cutPreviewBounds} />
              <Polygon
                positions={selectedCutGeoJson}
                pathOptions={{
                  color: '#1890ff',
                  weight: 2,
                  fillColor: '#1890ff',
                  fillOpacity: 0.15,
                }}
              />
            </MapContainer>
          </div>
        </Card>
      );
    }

    // No area configured yet
    return (
      <Card size="small" style={{ marginTop: 12 }}>
        <Text type="secondary" style={{ display: 'block', textAlign: 'center', padding: 16 }}>
          Select an area type above to see preview
        </Text>
      </Card>
    );
  };

  // ─── Steps ─────────────────────────────────────────────────────────

  const steps = [
    {
      title: 'Define Area',
      content: (
        <div>
          <div style={{ marginBottom: 16 }}>
            <Text strong>Area Source:</Text>
            <Select
              value={areaType}
              onChange={(val) => setAreaType(val)}
              style={{ width: 200, marginLeft: 12 }}
              options={[
                { value: 'cut', label: 'From Cut Boundary' },
                { value: 'viewport', label: 'From Map Settings' },
              ]}
            />
          </div>

          {areaType === 'cut' && (
            <div>
              <Text type="secondary" style={{ display: 'block', marginBottom: 8 }}>
                Select a cut polygon to define the import area.
              </Text>
              <Select
                placeholder="Select a cut..."
                value={selectedCutId}
                onChange={setSelectedCutId}
                style={{ width: '100%' }}
                showSearch
                optionFilterProp="label"
                options={cuts.map((c) => ({ value: c.id, label: c.name }))}
              />
            </div>
          )}

          {areaType === 'viewport' && (
            <div>
              {mapSettingsLoading ? (
                <Spin size="small" />
              ) : mapSettings?.latitude && mapSettings?.longitude ? (
                <>
                  <Card size="small">
                    <Row gutter={16}>
                      <Col span={6}>
                        <Statistic title="Center Lat" value={Number(mapSettings.latitude).toFixed(4)} valueStyle={{ fontSize: 16 }} />
                      </Col>
                      <Col span={6}>
                        <Statistic title="Center Lng" value={Number(mapSettings.longitude).toFixed(4)} valueStyle={{ fontSize: 16 }} />
                      </Col>
                      <Col span={6}>
                        <Statistic title="Zoom" value={effectiveZoom} valueStyle={{ fontSize: 16 }} />
                      </Col>
                      <Col span={6}>
                        <Statistic
                          title="Area"
                          value={viewportAreaSqKm ? viewportAreaSqKm.toFixed(0) : '—'}
                          suffix="km2"
                          valueStyle={{ fontSize: 16 }}
                        />
                      </Col>
                    </Row>
                  </Card>

                  <div style={{ marginTop: 12 }}>
                    <Text strong style={{ display: 'block', marginBottom: 4 }}>Zoom Level Override:</Text>
                    <Select
                      value={effectiveZoom}
                      onChange={(val) => setZoomOverride(val)}
                      style={{ width: '100%' }}
                      options={[
                        { value: mapSettings.zoom ?? 13, label: `Map Settings Default (zoom ${mapSettings.zoom ?? 13})` },
                        ...ZOOM_PRESETS.filter((p) => p.value !== (mapSettings.zoom ?? 13)),
                      ]}
                    />
                    <Text type="secondary" style={{ fontSize: 12, marginTop: 4, display: 'block' }}>
                      Lower zoom = larger area. Use "City-wide" for full city imports.
                    </Text>
                  </div>

                  {viewportAreaSqKm !== null && viewportAreaSqKm < 50 && (
                    <Alert
                      message="Small Coverage Area"
                      description={`This covers only ${viewportAreaSqKm.toFixed(0)} km2. Consider using a lower zoom level for city-wide imports.`}
                      type="warning"
                      showIcon
                      icon={<WarningOutlined />}
                      style={{ marginTop: 12 }}
                    />
                  )}
                </>
              ) : (
                <Alert
                  message="Map settings not configured"
                  description="Please set a center and zoom level in Map Settings first."
                  type="warning"
                  showIcon
                />
              )}
            </div>
          )}

          {renderPreviewMap()}
        </div>
      ),
    },
    {
      title: 'Sources',
      content: (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <Card
            size="small"
            style={{ borderColor: osmEnabled ? '#1890ff' : undefined, cursor: 'pointer' }}
            onClick={() => setOsmEnabled(!osmEnabled)}
          >
            <Checkbox checked={osmEnabled} onChange={(e) => { e.stopPropagation(); setOsmEnabled(e.target.checked); }}>
              <Space>
                <GlobalOutlined />
                <Text strong>OpenStreetMap (Overpass API)</Text>
              </Space>
            </Checkbox>
            <Text type="secondary" style={{ display: 'block', marginLeft: 24, fontSize: 12 }}>
              Fetches address nodes and building footprints from OSM. Best for urban areas with good community mapping.
            </Text>
          </Card>

          <Card
            size="small"
            style={{ borderColor: narEnabled ? '#1890ff' : undefined, cursor: 'pointer' }}
            onClick={() => setNarEnabled(!narEnabled)}
          >
            <Checkbox checked={narEnabled} onChange={(e) => { e.stopPropagation(); setNarEnabled(e.target.checked); }}>
              <Space>
                <DatabaseOutlined />
                <Text strong>NAR (National Address Register)</Text>
              </Space>
            </Checkbox>
            <Text type="secondary" style={{ display: 'block', marginLeft: 24, fontSize: 12 }}>
              Official Canadian address data. Requires NAR files on server. Highest priority for deduplication.
            </Text>
            {narEnabled && (
              <div style={{ marginLeft: 24, marginTop: 8 }} onClick={(e) => e.stopPropagation()}>
                <Checkbox checked={narResidentialOnly} onChange={(e) => setNarResidentialOnly(e.target.checked)}>
                  Residential only
                </Checkbox>
              </div>
            )}
          </Card>

          <Card
            size="small"
            style={{ borderColor: rgEnabled ? '#1890ff' : undefined, cursor: 'pointer' }}
            onClick={() => setRgEnabled(!rgEnabled)}
          >
            <Checkbox checked={rgEnabled} onChange={(e) => { e.stopPropagation(); setRgEnabled(e.target.checked); }}>
              <Space>
                <CompassOutlined />
                <Text strong>Reverse Geocode Grid</Text>
              </Space>
            </Checkbox>
            <Text type="secondary" style={{ display: 'block', marginLeft: 24, fontSize: 12 }}>
              Lays a grid of points and reverse geocodes each one. Slow but fills gaps not covered by other sources. Low confidence (40).
            </Text>
            {rgEnabled && (
              <div style={{ marginLeft: 24, marginTop: 8 }} onClick={(e) => e.stopPropagation()}>
                <Space direction="vertical" style={{ width: '100%' }}>
                  <div>
                    <Text style={{ fontSize: 12 }}>Grid spacing (meters):</Text>
                    <Slider min={20} max={500} step={10} value={rgSpacing} onChange={setRgSpacing} />
                  </div>
                  <div>
                    <Text style={{ fontSize: 12 }}>Max points: </Text>
                    <InputNumber min={10} max={2000} value={rgMaxPoints} onChange={(v) => v && setRgMaxPoints(v)} size="small" />
                  </div>
                </Space>
              </div>
            )}
          </Card>

          {!canProceedStep1 && (
            <Alert message="Select at least one source to continue." type="info" showIcon />
          )}
        </div>
      ),
    },
    {
      title: 'Preview',
      content: (
        <div>
          {previewLoading && (
            <div style={{ textAlign: 'center', padding: 24 }}>
              <Spin size="large" />
              <div style={{ marginTop: 12 }}>
                <Text type="secondary">Estimating import size...</Text>
              </div>
            </div>
          )}

          {previewError && (
            <Alert message="Preview Error" description={previewError} type="error" showIcon style={{ marginBottom: 16 }} />
          )}

          {preview && !previewLoading && (
            <>
              <Row gutter={[16, 16]} style={{ marginBottom: 16 }}>
                <Col span={8}>
                  <Card size="small">
                    <Statistic title="Area" value={preview.areaSqKm.toFixed(2)} suffix="km2" valueStyle={{ fontSize: 16 }} />
                  </Card>
                </Col>
                <Col span={8}>
                  <Card size="small">
                    <Statistic title="Existing Locations" value={preview.existingLocations} valueStyle={{ fontSize: 16 }} />
                  </Card>
                </Col>
                <Col span={8}>
                  <Card size="small">
                    <Statistic
                      title="Est. Total"
                      value={
                        (preview.estimates.osm >= 0 ? preview.estimates.osm : 0) +
                        preview.estimates.nar +
                        preview.estimates.reverseGeocode
                      }
                      valueStyle={{ fontSize: 16 }}
                    />
                  </Card>
                </Col>
              </Row>

              <Card size="small" title="Estimated Candidates by Source" style={{ marginBottom: 16 }}>
                <Row gutter={16}>
                  {osmEnabled && (
                    <Col span={8}>
                      <Statistic
                        title={<Space><GlobalOutlined /> OSM</Space>}
                        value={preview.estimates.osm >= 0 ? preview.estimates.osm : '?'}
                        valueStyle={{ fontSize: 16 }}
                      />
                    </Col>
                  )}
                  {narEnabled && (
                    <Col span={8}>
                      <Statistic
                        title={<Space><DatabaseOutlined /> NAR</Space>}
                        value={preview.estimates.nar}
                        suffix={preview.narProvincesDetected.length > 0 ? '' : undefined}
                        valueStyle={{ fontSize: 16 }}
                      />
                      {preview.narProvincesDetected.length > 0 && (
                        <Text type="secondary" style={{ fontSize: 11 }}>
                          Provinces: {preview.narProvincesDetected.join(', ')}
                        </Text>
                      )}
                      {preview.narProvincesDetected.length === 0 && (
                        <Text type="warning" style={{ fontSize: 11 }}>No NAR data for this area</Text>
                      )}
                    </Col>
                  )}
                  {rgEnabled && (
                    <Col span={8}>
                      <Statistic
                        title={<Space><CompassOutlined /> Rev. Geocode</Space>}
                        value={preview.estimates.reverseGeocode}
                        suffix="points"
                        valueStyle={{ fontSize: 16 }}
                      />
                    </Col>
                  )}
                </Row>
              </Card>

              {(preview.estimates.osm + preview.estimates.nar + preview.estimates.reverseGeocode) > 10000 && (
                <Alert
                  message="Large Import"
                  description="Estimated candidates exceed 10,000. This may take a while. Consider narrowing the area or disabling reverse geocode."
                  type="warning"
                  showIcon
                  style={{ marginBottom: 16 }}
                />
              )}

              {preview.areaSqKm > 100 && osmEnabled && (
                <Alert
                  message="Large OSM Query"
                  description={`Area is ${preview.areaSqKm.toFixed(0)} km2. Large Overpass queries may be slow or fail. Consider using a private Overpass instance.`}
                  type="warning"
                  showIcon
                  style={{ marginBottom: 16 }}
                />
              )}

              <Button
                type="primary"
                size="large"
                block
                onClick={startImport}
                loading={importing}
              >
                Start Import
              </Button>
            </>
          )}
        </div>
      ),
    },
    {
      title: 'Progress',
      content: (
        <div>
          {progress ? (
            <>
              {progress.status === 'complete' ? (
                <Result
                  status="success"
                  title="Import Complete"
                  subTitle={`${progress.locationsCreated} locations and ${progress.addressesCreated} addresses created`}
                  extra={[
                    <Button key="done" type="primary" onClick={() => onComplete?.()}>
                      Done
                    </Button>,
                  ]}
                />
              ) : progress.status === 'failed' ? (
                <Result
                  status="error"
                  title="Import Failed"
                  subTitle={progress.error || 'An unknown error occurred'}
                  extra={[
                    <Button key="back" onClick={() => { setCurrentStep(2); setImporting(false); }}>
                      Back to Preview
                    </Button>,
                  ]}
                />
              ) : (
                <>
                  <Title level={5} style={{ marginBottom: 16 }}>
                    {progress.status === 'initializing' ? 'Initializing...' :
                     progress.status === 'creating-records' ? 'Creating records...' : 'Running sources...'}
                  </Title>

                  <Card size="small" title="Source Progress" style={{ marginBottom: 16 }}>
                    {(['osm', 'nar', 'reverseGeocode'] as const).map((source) => {
                      const sp = progress.sources[source];
                      const labels = { osm: 'OpenStreetMap', nar: 'NAR', reverseGeocode: 'Reverse Geocode' };
                      return (
                        <div key={source} style={{ marginBottom: 8 }}>
                          <Space>
                            {SOURCE_STATUS_ICONS[sp.status]}
                            <Text strong>{labels[source]}</Text>
                            <Tag>{sp.status}</Tag>
                            {sp.candidatesFound > 0 && (
                              <Text type="secondary">{sp.candidatesFound} found</Text>
                            )}
                            {sp.failedQuadrants && sp.failedQuadrants > 0 && (
                              <Tag color="warning">{sp.failedQuadrants} quadrant(s) failed</Tag>
                            )}
                          </Space>
                          {sp.message && (
                            <Text type="secondary" style={{ display: 'block', marginLeft: 24, fontSize: 12 }}>
                              {sp.message}
                            </Text>
                          )}
                          {sp.error && (
                            <Text type="danger" style={{ display: 'block', marginLeft: 24, fontSize: 12 }}>
                              {sp.error}
                            </Text>
                          )}
                        </div>
                      );
                    })}
                  </Card>

                  <Row gutter={16}>
                    <Col span={8}>
                      <Statistic title="Locations Created" value={progress.locationsCreated} valueStyle={{ fontSize: 16, color: '#52c41a' }} />
                    </Col>
                    <Col span={8}>
                      <Statistic title="Addresses Created" value={progress.addressesCreated} valueStyle={{ fontSize: 16, color: '#52c41a' }} />
                    </Col>
                    <Col span={8}>
                      <Statistic title="Duplicates Skipped" value={progress.skippedDuplicate} valueStyle={{ fontSize: 16, color: '#faad14' }} />
                    </Col>
                  </Row>

                  {progress.status === 'creating-records' && progress.totalCandidates > 0 && (
                    <Progress
                      percent={Math.round((progress.locationsCreated / progress.totalCandidates) * 100)}
                      style={{ marginTop: 16 }}
                      status="active"
                    />
                  )}
                </>
              )}
            </>
          ) : (
            <div style={{ textAlign: 'center', padding: 24 }}>
              <Spin size="large" />
              <div style={{ marginTop: 12 }}>
                <Text type="secondary">Starting import...</Text>
              </div>
            </div>
          )}
        </div>
      ),
    },
  ];

  const handleNext = () => {
    if (currentStep === 1) {
      // Moving to preview step — fetch preview
      setCurrentStep(2);
      // Fetch preview after state update
      setTimeout(() => fetchPreview(), 0);
    } else {
      setCurrentStep(currentStep + 1);
    }
  };

  return (
    <div>
      <Steps
        current={currentStep}
        size="small"
        style={{ marginBottom: 24 }}
        items={steps.map((s) => ({ title: s.title }))}
      />

      <div style={{ minHeight: 200 }}>
        {steps[currentStep]?.content}
      </div>

      {currentStep < 2 && (
        <div style={{ marginTop: 16, display: 'flex', justifyContent: 'space-between' }}>
          <Button disabled={currentStep === 0} onClick={() => setCurrentStep(currentStep - 1)}>
            Back
          </Button>
          <Button
            type="primary"
            onClick={handleNext}
            disabled={currentStep === 0 ? !canProceedStep0 : !canProceedStep1}
          >
            Next
          </Button>
        </div>
      )}

      {currentStep === 2 && !previewLoading && !preview && !previewError && (
        <div style={{ marginTop: 16, display: 'flex', justifyContent: 'space-between' }}>
          <Button onClick={() => setCurrentStep(1)}>Back</Button>
          <Button type="primary" onClick={fetchPreview}>Load Preview</Button>
        </div>
      )}

      {currentStep === 2 && (preview || previewError) && !importing && (
        <div style={{ marginTop: 16 }}>
          <Button onClick={() => { setCurrentStep(1); setPreview(null); setPreviewError(null); }}>Back</Button>
        </div>
      )}
    </div>
  );
}
