const express = require("express");
const router = express.Router();
const { authenticateToken } = require("../middleware/auth");
const rateLimiter = require("../middleware/rateLimiter");
const googleMapsService = require("../services/googleMapsService");
const logger = require("../utils/logger");

// Input validation middleware
const validateInput = (req, res, next) => {
  // Basic input sanitization
  if (req.body.input) {
    req.body.input = req.body.input.toString().trim();
    // Prevent extremely long inputs
    if (req.body.input.length > 500) {
      return res.status(400).json({ error: "Input too long" });
    }
  }

  if (req.body.placeId) {
    req.body.placeId = req.body.placeId.toString().trim();
    // Basic place ID validation
    if (!/^[A-Za-z0-9_-]+$/.test(req.body.placeId)) {
      return res.status(400).json({ error: "Invalid place ID format" });
    }
  }

  if (req.body.address) {
    req.body.address = req.body.address.toString().trim();
    if (req.body.address.length > 500) {
      return res.status(400).json({ error: "Address too long" });
    }
  }

  next();
};

// Error handling middleware
const handleServiceError = (error, res, req) => {
  const reqLogger = logger.withRequestId(req?.id);
  reqLogger.error("Maps service error", {
    error: error.message,
    stack: error.stack
  });

  if (error.message.includes("API key not configured")) {
    return res.status(503).json({
      error: "Maps service temporarily unavailable",
      details: "Configuration issue",
    });
  }

  if (error.message.includes("quota exceeded")) {
    return res.status(429).json({
      error: "Service temporarily unavailable due to high demand",
      details: "Please try again later",
    });
  }

  return res.status(500).json({
    error: "Failed to process request",
    details: error.message,
  });
};

/**
 * POST /api/maps/places/autocomplete
 * Proxy for Google Places Autocomplete API
 */
router.post(
  "/places/autocomplete",
  authenticateToken,
  rateLimiter.placesAutocomplete,
  validateInput,
  async (req, res) => {
    try {
      const { input, types, componentRestrictions, sessionToken } = req.body;

      if (!input || input.length < 2) {
        return res.json({ predictions: [] });
      }

      const options = {
        types: types || ["address"],
        componentRestrictions,
        sessionToken,
      };

      const result = await googleMapsService.getPlacesAutocomplete(
        input,
        options
      );

      // Log request for monitoring (without sensitive data)
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Places Autocomplete request", {
        userId: req.user?.id || "anonymous",
        queryLength: input.length,
        resultsCount: result.predictions?.length || 0
      });

      res.json(result);
    } catch (error) {
      handleServiceError(error, res, req);
    }
  }
);

/**
 * POST /api/maps/places/details
 * Proxy for Google Places Details API
 */
router.post(
  "/places/details",
  authenticateToken,
  rateLimiter.placeDetails,
  validateInput,
  async (req, res) => {
    try {
      const { placeId, sessionToken } = req.body;

      if (!placeId) {
        return res.status(400).json({ error: "Place ID is required" });
      }

      const options = {
        sessionToken,
      };

      const result = await googleMapsService.getPlaceDetails(placeId, options);

      // Log request for monitoring
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Place Details request", {
        userId: req.user?.id || "anonymous",
        placeIdPrefix: placeId.substring(0, 10) + "..."
      });

      res.json(result);
    } catch (error) {
      handleServiceError(error, res, req);
    }
  }
);

/**
 * POST /api/maps/geocode
 * Proxy for Google Geocoding API
 */
router.post(
  "/geocode",
  authenticateToken,
  rateLimiter.geocoding,
  validateInput,
  async (req, res) => {
    try {
      const { address, componentRestrictions } = req.body;

      if (!address) {
        return res.status(400).json({ error: "Address is required" });
      }

      const options = {
        componentRestrictions,
      };

      const result = await googleMapsService.geocodeAddress(address, options);

      // Log request for monitoring
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Geocoding request", {
        userId: req.user?.id || "anonymous",
        addressLength: address.length
      });

      res.json(result);
    } catch (error) {
      handleServiceError(error, res, req);
    }
  }
);

/**
 * GET /api/maps/health
 * Health check endpoint for Maps service
 */
router.get("/health", (req, res) => {
  const isConfigured = googleMapsService.isConfigured();

  res.status(isConfigured ? 200 : 503).json({
    status: isConfigured ? "healthy" : "unavailable",
    service: "Google Maps API Proxy",
    timestamp: new Date().toISOString(),
    configuration: {
      apiKeyConfigured: isConfigured,
    },
  });
});

module.exports = router;
