const express = require('express');
const cors = require('cors');

const app = express();
const PORT = 8000;

// Middleware
app.use(cors());
app.use(express.json());

// Swiss cantons for validation
const SWISS_CANTONS = {
  // Map of postal code prefixes to cantons
  '1': 'VD/GE/VS/FR/NE',  // 1000-1999
  '2': 'NE/JU/BE',        // 2000-2999
  '3': 'BE/FR/SO/VS',     // 3000-3999
  '4': 'BS/BL/AG/SO/JU',  // 4000-4999
  '5': 'AG/ZH/SO',        // 5000-5999
  '6': 'LU/ZG/NW/OW/UR/TI', // 6000-6999
  '7': 'GR',              // 7000-7999
  '8': 'ZH/SH/TG/SG/GL',  // 8000-8999
  '9': 'SG/AR/AI/TG/GL',  // 9000-9999
};

// Common street types in Switzerland
const STREET_TYPES = [
  'strasse', 'str.', 'str', 'weg', 'gasse', 'platz', 'allee', 'avenue', 'ave', 
  'boulevard', 'promenade', 'quartier', 'rue', 'route', 'chemin', 'via', 'corso'
];

// Swiss address format validation
function validateSwissAddress(address) {
  // Looking for patterns like street name + number, postal code (4 digits) + city
  
  const addressComponents = {
    street: null,
    houseNumber: null,
    postalCode: null,
    city: null,
    canton: null,
    valid: false,
    formattedAddress: address,
    confidence: 0 // 0-100 confidence score
  };
  
  // Clean and normalize the address
  const cleanAddress = address.replace(/\s+/g, ' ')
                             .replace(/,\s*/g, ', ')
                             .trim();
  
  // First try to match standard Swiss format: Street Number, PostalCode City
  const fullMatch = cleanAddress.match(
    /([A-Za-zäöüÄÖÜß\s\.-]+[\s-]+\d+\w*),?\s*(\d{4})\s+([A-Za-zäöüÄÖÜß\s\.-]+)/i
  );
  
  if (fullMatch) {
    addressComponents.street = fullMatch[1].trim().replace(/\s+(\d+\w*)$/, '');
    addressComponents.houseNumber = fullMatch[1].match(/(\d+\w*)$/)[1];
    addressComponents.postalCode = fullMatch[2];
    addressComponents.city = fullMatch[3].trim();
    addressComponents.confidence = 90;
  } else {
    // Try to extract components individually
    
    // Extract street with house number - more flexible pattern
    let streetMatch = null;
    
    // First try to find a street with a known suffix
    for (const type of STREET_TYPES) {
      const regex = new RegExp(`([A-Za-zäöüÄÖÜß\\s\\.-]+(${type})\\s+)(\\d+\\w*)`, 'i');
      const match = cleanAddress.match(regex);
      if (match) {
        streetMatch = match;
        addressComponents.confidence += 20;
        break;
      }
    }
    
    // If no match with known street types, try generic pattern
    if (!streetMatch) {
      streetMatch = cleanAddress.match(/([A-Za-zäöüÄÖÜß\s\.-]+)(?:\s+)(\d+\w*)/i);
      if (streetMatch) {
        addressComponents.confidence += 10;
      }
    }
    
    if (streetMatch) {
      addressComponents.street = streetMatch[1].trim();
      addressComponents.houseNumber = streetMatch[2];
    }
    
    // Extract postal code (4 digits in Switzerland) and city
    const postalCityMatch = cleanAddress.match(/\b(\d{4})\s+([A-Za-zäöüÄÖÜß\s\.-]+)\b/i);
    if (postalCityMatch) {
      addressComponents.postalCode = postalCityMatch[1];
      addressComponents.city = postalCityMatch[2].trim();
      addressComponents.confidence += 40;
      
      // Determine canton from postal code
      const postalPrefix = postalCityMatch[1].charAt(0);
      addressComponents.canton = SWISS_CANTONS[postalPrefix] || null;
      if (addressComponents.canton) {
        addressComponents.confidence += 10;
      }
    }
  }
  
  // Check if we have the essential components
  if (addressComponents.street && addressComponents.postalCode && addressComponents.city) {
    addressComponents.valid = true;
    
    // Format the address in a standardized Swiss way
    addressComponents.formattedAddress = `${addressComponents.street} ${addressComponents.houseNumber}, ${addressComponents.postalCode} ${addressComponents.city}`;
    
    // Add canton if available
    if (addressComponents.canton) {
      addressComponents.formattedAddress += ` (${addressComponents.canton})`;
    }
  }
  
  return addressComponents;
}

// Endpoint for address validation
app.post('/api/validate-address', (req, res) => {
  const { address } = req.body;
  
  if (!address) {
    return res.status(400).json({ 
      message: 'Address is required',
      success: false 
    });
  }
  
  console.log('Validating address:', address);
  
  // Validate the address
  const validationResult = validateSwissAddress(address);
  
  if (validationResult.valid) {
    console.log('Address is valid:', validationResult.formattedAddress);
    console.log('Confidence score:', validationResult.confidence);
    return res.json(validationResult.formattedAddress);
  } else {
    console.log('Address validation failed, returning original:', address);
    // Return the original address if validation fails
    return res.json(address);
  }
});

// Endpoint for detailed address validation
app.post('/api/validate-address/detailed', (req, res) => {
  const { address } = req.body;
  
  if (!address) {
    return res.status(400).json({ 
      success: false,
      message: 'Address is required'
    });
  }
  
  console.log('Performing detailed validation for:', address);
  
  // Validate the address
  const validationResult = validateSwissAddress(address);
  
  // Return the full validation result for detailed analysis
  return res.json({
    success: validationResult.valid,
    original: address,
    formatted: validationResult.formattedAddress,
    components: {
      street: validationResult.street,
      houseNumber: validationResult.houseNumber,
      postalCode: validationResult.postalCode,
      city: validationResult.city,
      canton: validationResult.canton
    },
    confidence: validationResult.confidence,
    valid: validationResult.valid
  });
});

// Mock address lookup endpoint for testing
app.get('/api/address-lookup', (req, res) => {
  const { postalCode, city } = req.query;
  
  if (!postalCode && !city) {
    return res.status(400).json({
      success: false,
      message: 'Postal code or city is required'
    });
  }
  
  // Sample street data for common Swiss cities
  const streetData = {
    // Bern
    '3000': [
      'Bundesplatz', 'Bahnhofstrasse', 'Marktgasse', 'Spitalgasse', 'Kramgasse',
      'Münstergasse', 'Gerechtigkeitsgasse', 'Postgasse', 'Aarbergergasse'
    ],
    // Zürich
    '8000': [
      'Bahnhofstrasse', 'Rämistrasse', 'Uraniastrasse', 'Limmatquai', 'Talstrasse',
      'Seefeldstrasse', 'Bellerivestrasse', 'Mythengasse', 'Europaallee'
    ],
    // Basel
    '4000': [
      'Freiestrasse', 'Steinenvorstadt', 'Marktplatz', 'Gerbergasse', 'Spalenberg',
      'Greifengasse', 'Rheingasse', 'Clarastrasse', 'St. Alban-Vorstadt'
    ],
    // Lausanne
    '1000': [
      'Rue du Petit-Chêne', 'Avenue du Léman', 'Rue de Bourg', 'Place de la Palud',
      'Avenue de Cour', 'Rue Centrale', 'Route de Berne'
    ]
  };
  
  // Default response
  let streets = [];
  
  if (postalCode && streetData[postalCode]) {
    streets = streetData[postalCode];
  } else if (city) {
    // Map city names to postal codes
    const cityMap = {
      'bern': '3000',
      'zürich': '8000',
      'zurich': '8000',
      'basel': '4000',
      'lausanne': '1000'
    };
    
    const normalizedCity = city.toLowerCase();
    if (cityMap[normalizedCity] && streetData[cityMap[normalizedCity]]) {
      streets = streetData[cityMap[normalizedCity]];
    }
  }
  
  return res.json({
    success: true,
    streets: streets.map(street => ({ 
      name: street, 
      postalCode: postalCode || '' 
    }))
  });
});

// Health check endpoint
app.get('/api/health', (req, res) => {
  res.json({ status: 'up', message: 'Address validation service is running' });
});

// Start the server
app.listen(PORT, () => {
  console.log(`Address validation service running on http://localhost:${PORT}`);
  console.log(`Test the service at http://localhost:${PORT}/api/health`);
});
