/**
 * Main Application Entry Point
 *
 * Demonstrates integration of:
 * - Bootstrap 5.3 for UI components
 * - SQLocal (SQLite in browser via OPFS)
 * - BroadcastChannel for cross-tab sync
 * - OpenLayers map with ol-ext LayerSwitcher
 * - PWA features (Service Worker, install prompt, offline detection)
 */

// Bootstrap CSS and JS
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap-icons/font/bootstrap-icons.css';
import { Modal, Offcanvas } from 'bootstrap';

// Database module (uses SQLocal directly, BroadcastChannel for tab sync)
import {
  sql,
  dbReady,
  initSchema,
  addLocation,
  getLocations,
  getLocationCount,
  getDatabaseStatus,
  downloadDatabase,
  onDatabaseChange,
  exportToGeoJSON
} from './src/database.js';

// Map component with OpenLayers and ol-ext LayerSwitcher
import { MapView } from './src/components/MapView.js';

// Map measurement and drawing tools
import { MapTools } from './src/components/MapTools.js';

// PWA module (registers Service Worker, handles install/offline)
import { initPWA, isOnline, onOfflineChange } from './src/pwa.js';

// Map instance (global for access across functions)
let mapView = null;
let mapTools = null;

// Current interaction mode: 'addLocation' | 'measureCircle' | 'measureLine' | 'measureArea'
let currentMode = 'addLocation';

// ============================================================================
// Application Initialization
// ============================================================================

async function initApp() {
  console.log('[App] Initializing...');

  // 1. Initialize PWA features (Service Worker, install prompt, offline detection)
  await initPWA({
    installButton: '#install-btn',
    offlineIndicator: '#offline-indicator',
    autoRegisterSW: true
  });

  // 2. Initialize the map
  mapView = new MapView('map', {
    center: [-1.5, 7.5],  // Ghana
    zoom: 7,
    basemap: 'osm'
  });

  // Initialize map measurement tools
  mapTools = new MapTools(mapView.getMap());

  // Log measurement results
  mapTools.onMeasureComplete((result) => {
    console.log('[MapTools] Measurement complete:', result);
  });

  // Category emojis are set up in MapView:
  // 'water': '💧', 'school': '🏫', 'health': '🏥',
  // 'market': '🏪', 'default': '📍', 'other': '📌'

  // Set up map click handler immediately after map creation
  mapView.onClick((lon, lat, feature, evt) => {
    console.log('[MapClick] Clicked at:', lon.toFixed(4), lat.toFixed(4));
    console.log('[MapClick] currentMode =', currentMode);
    console.log('[MapClick] typeof currentMode =', typeof currentMode);

    // Only handle location-related clicks in addLocation mode
    if (currentMode !== 'addLocation') {
      console.log('[MapClick] NOT in addLocation mode, skipping popup');
      return;
    }

    console.log('[MapClick] IN addLocation mode, processing...');

    if (feature) {
      // Clicked on existing marker - select it and show details
      console.log('[MapClick] Clicked on feature:', feature.getId());
      mapView.selectMarker(feature);
      showLocationDetails(feature);
    } else {
      // Clicked on empty space - show add location popup at click position
      console.log('[MapClick] Clicked on empty space, showing popup');
      mapView.clearSelection();
      mapView.showAddLocationPopup(evt.coordinate);
    }
  });

  // Set up handler for the map add location popup form
  mapView.onAddLocation(async (data) => {
    console.log('[App] Add location from map popup:', data);
    try {
      const result = await addLocation(data.name, data.lon, data.lat, {
        description: data.description || null,
        category: data.category || 'default'
      });
      console.log('[App] Location added:', data.name, 'id:', result.id);

      await loadLocations();

      // Zoom to the new location on the map
      mapView?.zoomTo(data.lon, data.lat, 14);

      // Select the new marker
      if (result.id) {
        mapView?.selectMarker(result.id);
      }

      showSuccess('Location added successfully');

    } catch (error) {
      console.error('[App] Failed to add location:', error);
      showError('Failed to add location: ' + error.message);
    }
  });

  // 3. Initialize database
  try {
    console.log('[App] Initializing database...');

    // Initialize schema (creates tables if they don't exist)
    // This also resolves dbReady when complete
    await initSchema();

    // Now dbReady should be resolved
    console.log('[App] Database ready');

    // Show database status
    const status = await getDatabaseStatus();
    console.log('[App] Database status:', status);

  } catch (error) {
    console.error('[App] Database initialization failed:', error);
    showError('Failed to initialize database. Please refresh the page.');
    return;
  }

  // 4. Initialize UI
  initUI();

  // 5. Load initial data and display on map
  await loadLocations();

  // 6. Listen for database changes from other tabs
  onDatabaseChange((change) => {
    console.log('[App] Database change:', change);
    if (change.table === 'locations' && !change.local) {
      // Reload locations when another tab makes changes
      loadLocations();
    }
  });

  // 7. Set up offline handling
  onOfflineChange((offline) => {
    if (offline) {
      console.log('[App] Working offline - data will sync when back online');
    } else {
      console.log('[App] Back online - syncing data...');
      syncData();
    }
  });

  console.log('[App] Initialized successfully');
}

// ============================================================================
// UI Initialization
// ============================================================================

function initUI() {
  console.log('[initUI] Starting UI initialization...');

  // Export button
  const exportBtn = document.getElementById('export-btn');
  if (exportBtn) {
    exportBtn.addEventListener('click', handleExport);
  }

  // GeoJSON Export button
  const exportGeoJSONBtn = document.getElementById('exportGeoJSON-btn');
  if (exportGeoJSONBtn) {
    exportGeoJSONBtn.addEventListener('click', handleExportGeoJSON);
  }

  // Status button
  const statusBtn = document.getElementById('status-btn');
  if (statusBtn) {
    statusBtn.addEventListener('click', handleShowStatus);
  }

  // Fit to markers button
  const fitBtn = document.getElementById('fit-btn');
  if (fitBtn) {
    fitBtn.addEventListener('click', () => mapView?.fitToMarkers());
  }

  // ============================================
  // Mode Selector & Measurement Tools (Bottom Dock)
  // ============================================

  const addLocationBtn = document.getElementById('dock-btn-add-location');
  const measureCircleBtn = document.getElementById('dock-btn-measure-circle');
  const measureLineBtn = document.getElementById('dock-btn-measure-line');
  const measureAreaBtn = document.getElementById('dock-btn-measure-area');
  const clearBtn = document.getElementById('dock-btn-clear');

  // Debug: Check if buttons are found
  console.log('[initUI] Buttons found:', {
    addLocation: !!addLocationBtn,
    measureCircle: !!measureCircleBtn,
    measureLine: !!measureLineBtn,
    measureArea: !!measureAreaBtn,
    clear: !!clearBtn
  });

  // All mode buttons (mutually exclusive)
  const modeButtons = [addLocationBtn, measureCircleBtn, measureLineBtn, measureAreaBtn];

  // Helper to set active mode and update button states
  // Note: This updates the module-level currentMode variable
  const setMode = (mode, activeBtn) => {
    console.log('[setMode] Changing mode from', currentMode, 'to', mode);
    currentMode = mode;
    console.log('[setMode] currentMode is now:', currentMode);

    // Update button active states
    modeButtons.forEach(btn => {
      if (btn) btn.classList.toggle('active', btn === activeBtn);
    });

    // Deactivate any measurement tool when switching modes
    mapTools?.deactivate();

    // Hide add location popup when leaving addLocation mode
    if (mode !== 'addLocation') {
      mapView?.hideAddLocationPopup();
    }

    // Activate the appropriate measurement tool
    switch (mode) {
      case 'measureCircle':
        mapTools?.startCircleMeasure();
        break;
      case 'measureLine':
        mapTools?.startLineMeasure();
        break;
      case 'measureArea':
        mapTools?.startAreaMeasure();
        break;
      // addLocation mode doesn't need tool activation
    }
  };

  // Add Location mode button
  if (addLocationBtn) {
    addLocationBtn.addEventListener('click', () => {
      console.log('[Button] Add Location clicked');
      setMode('addLocation', addLocationBtn);
    });
  }

  // Circle measurement button
  if (measureCircleBtn) {
    measureCircleBtn.addEventListener('click', () => {
      console.log('[Button] Circle clicked, currentMode is:', currentMode);
      if (currentMode === 'measureCircle') {
        // Toggle off - return to addLocation mode
        setMode('addLocation', addLocationBtn);
      } else {
        setMode('measureCircle', measureCircleBtn);
}
    });
  }

  // Line measurement button
  if (measureLineBtn) {
    measureLineBtn.addEventListener('click', () => {
      console.log('[Button] Line clicked, currentMode is:', currentMode);
      if (currentMode === 'measureLine') {
        setMode('addLocation', addLocationBtn);
      } else {
        setMode('measureLine', measureLineBtn);
      }
    });
  }

  // Area measurement button
  if (measureAreaBtn) {
    measureAreaBtn.addEventListener('click', () => {
      console.log('[Button] Area clicked, currentMode is:', currentMode);
      if (currentMode === 'measureArea') {
        setMode('addLocation', addLocationBtn);
      } else {
        setMode('measureArea', measureAreaBtn);
      }
    });
  }

  // Clear button - clears measurements but stays in current mode
  if (clearBtn) {
    clearBtn.addEventListener('click', () => {
      mapTools?.clearMeasurements();
      // If in a measurement mode, restart the tool
      if (currentMode.startsWith('measure')) {
      mapTools?.deactivate();
        switch (currentMode) {
          case 'measureCircle':
            mapTools?.startCircleMeasure();
            break;
          case 'measureLine':
            mapTools?.startLineMeasure();
            break;
          case 'measureArea':
            mapTools?.startAreaMeasure();
            break;
        }
      }
    });
  }
}

// ============================================================================
// Location Handlers
// ============================================================================

async function handleAddLocation(event) {
  event.preventDefault();

  const form = event.target;
  const formData = new FormData(form);

  const name = formData.get('name');
  const longitude = parseFloat(formData.get('longitude'));
  const latitude = parseFloat(formData.get('latitude'));
  const description = formData.get('description') || null;
  const category = formData.get('category') || 'default';

  if (!name || isNaN(longitude) || isNaN(latitude)) {
    showError('Please fill in all required fields');
    return;
  }

  try {
    const result = await addLocation(name, longitude, latitude, { description, category });
    console.log('[App] Location added:', name, 'id:', result.id);

    form.reset();
    await loadLocations();

    // Zoom to the new location on the map
    mapView?.zoomTo(longitude, latitude, 14);

    // Select the new marker
    if (result.id) {
      mapView?.selectMarker(result.id);
    }

    showSuccess('Location added successfully');

  } catch (error) {
    console.error('[App] Failed to add location:', error);
    showError('Failed to add location: ' + error.message);
  }
}

async function loadLocations() {
  try {
    console.log('[App] Loading locations...');
    const locations = await getLocations();
    console.log('[App] Locations loaded:', locations);

    // Update the list
    renderLocations(locations);

    // Update the map markers
    if (mapView) {
      mapView.clearMarkers();
      if (locations.length > 0) {
        mapView.addMarkers(locations);
        console.log('[App] Added', locations.length, 'markers to map');
      }
    }

    // Update count display
    const countEl = document.getElementById('location-count');
    if (countEl) {
      countEl.textContent = locations.length;
    }

  } catch (error) {
    console.error('[App] Failed to load locations:', error);
  }
}

/**
 * Show details for a selected location
 */
function showLocationDetails(feature) {
  const name = feature.get('name');
  const description = feature.get('description');
  const category = feature.get('category');
  const lon = feature.get('lon') || feature.get('longitude');
  const lat = feature.get('lat') || feature.get('latitude');

  // You could show a popup or info panel here
  // For now, just log to console
  console.log('[App] Selected location:', { name, description, category, lon, lat });

  // Optionally zoom to the location
  // mapView.zoomTo(lon, lat, 14);
}

function renderLocations(locations) {
  const container = document.getElementById('locations-list');
  if (!container) return;

  // Also update mobile count
  const mobileCount = document.getElementById('location-count-mobile');
  if (mobileCount) {
    mobileCount.textContent = locations.length;
  }

  if (locations.length === 0) {
    container.innerHTML = `
      <div class="text-center text-muted py-4">
        <p class="mb-0">No locations yet.</p>
        <small>Click the map or fill the form above!</small>
      </div>
    `;
    return;
  }

  // Category emoji mapping
  const categoryEmojis = {
    'water': '💧',
    'school': '🏫',
    'health': '🏥',
    'market': '🏪',
    'default': '📍',
    'other': '📌'
  };

  container.innerHTML = locations.map(loc => {
    const emoji = categoryEmojis[loc.category] || '📍';
    return `
      <a href="#" class="list-group-item list-group-item-action location-item py-2"
         data-id="${loc.id}" data-lon="${loc.longitude}" data-lat="${loc.latitude}">
        <div class="d-flex w-100 justify-content-between align-items-start">
          <div>
            <h6 class="mb-1">${emoji} ${escapeHtml(loc.name)}</h6>
            <small class="text-muted font-monospace">${loc.latitude.toFixed(5)}, ${loc.longitude.toFixed(5)}</small>
          </div>
          <span class="badge badge-${loc.category}">${loc.category}</span>
        </div>
        ${loc.description ? `<small class="text-secondary d-block mt-1">${escapeHtml(loc.description)}</small>` : ''}
      </a>
    `;
  }).join('');

  // Add click handlers to zoom to location
  container.querySelectorAll('.location-item').forEach(item => {
    item.addEventListener('click', (e) => {
      e.preventDefault();
      const lon = parseFloat(item.dataset.lon);
      const lat = parseFloat(item.dataset.lat);
      const id = parseInt(item.dataset.id);

      // Zoom to location on map
      mapView?.zoomTo(lon, lat, 14);

      // Select the marker
      mapView?.selectMarker(id);
    });
  });
}

// ============================================================================
// Export Handler
// ============================================================================

async function handleExport() {
  try {
    await downloadDatabase('lupmis-backup.sqlite3');
    showSuccess('Database exported successfully');
  } catch (error) {
    console.error('[App] Export failed:', error);
    showError('Export failed: ' + error.message);
  }
}


// ============================================================================
// Status Handler
// ============================================================================

async function handleShowStatus() {
  try {
    const status = await getDatabaseStatus();

    // Update modal content
    const statusContent = document.getElementById('status-content');
    if (statusContent) {
      statusContent.innerHTML = `
        <table class="table table-sm table-borderless mb-0">
          <tbody>
            <tr>
              <td class="fw-semibold">Ready:</td>
              <td><span class="badge ${status.ready ? 'bg-success' : 'bg-danger'}">${status.ready ? 'Yes' : 'No'}</span></td>
            </tr>
            <tr>
              <td class="fw-semibold">Online:</td>
              <td><span class="badge ${isOnline() ? 'bg-success' : 'bg-warning'}">${isOnline() ? 'Yes' : 'Offline'}</span></td>
            </tr>
            <tr>
              <td class="fw-semibold">Database:</td>
              <td><code>${status.databasePath || 'N/A'}</code></td>
            </tr>
            <tr>
              <td class="fw-semibold">Tables:</td>
              <td>${status.tables.map(t => `<span class="badge bg-secondary me-1">${t}</span>`).join('')}</td>
            </tr>
            <tr>
              <td class="fw-semibold">Locations:</td>
              <td><span class="badge bg-primary">${status.locationCount}</span></td>
            </tr>
          </tbody>
        </table>
      `;
    }

    // Show the modal using Bootstrap
    const statusModal = new Modal(document.getElementById('statusModal'));
    statusModal.show();

  } catch (error) {
    console.error('[App] Failed to get status:', error);
    showError('Failed to get status');
  }
}

// ============================================================================
// Sync (placeholder - implement based on your backend)
// ============================================================================

async function syncData() {
  if (!isOnline()) {
    console.log('[App] Cannot sync - offline');
    return;
  }

  // TODO: Implement sync with your backend
  // Example:
  // const unsynced = await getUnsyncedLocations();
  // for (const location of unsynced) {
  //   await fetch('/api/locations', {
  //     method: 'POST',
  //     body: JSON.stringify(location)
  //   });
  //   await markLocationsSynced([location.id]);
  // }

  console.log('[App] Sync placeholder - implement based on your backend');
}

// ============================================================================
// Utilities
// ============================================================================

function escapeHtml(text) {
  const div = document.createElement('div');
  div.textContent = text;
  return div.innerHTML;
}

function showError(message) {
  const el = document.getElementById('error-message');
  if (el) {
    el.querySelector('.message-text').textContent = message;
    el.classList.remove('d-none');

    // Auto-hide after 5 seconds
    setTimeout(() => {
      el.classList.add('d-none');
    }, 5000);
  } else {
    console.error(message);
  }
}

function showSuccess(message) {
  const el = document.getElementById('success-message');
  if (el) {
    el.querySelector('.message-text').textContent = message;
    el.classList.remove('d-none');

    // Auto-hide after 3 seconds
    setTimeout(() => {
      el.classList.add('d-none');
    }, 3000);
  } else {
    console.log(message);
  }
}

// ============================================================================
// Start Application
// ============================================================================

// Wait for DOM to be ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initApp);
} else {
  initApp();
}
