const express = require("express");
const Street = require("../models/Street");
const User = require("../models/User");
const couchdbService = require("../services/couchdbService");
const auth = require("../middleware/auth");
const { asyncHandler } = require("../middleware/errorHandler");
const {
  createStreetValidation,
  streetIdValidation,
} = require("../middleware/validators/streetValidator");
const { getCacheMiddleware, invalidateCacheByPattern } = require("../middleware/cache");

const router = express.Router();

// Get all streets (with pagination and filtering)
router.get(
  "/",
  getCacheMiddleware(300), // Cache for 5 minutes
  asyncHandler(async (req, res) => {
    const { buildPaginatedResponse } = require("../middleware/pagination");

    // Parse pagination params
    const page = parseInt(req.query.page) || 1;
    const limit = Math.min(parseInt(req.query.limit) || 10, 100);
    const skip = (page - 1) * limit;

    // Parse filter params
    const { search, status, adoptedBy, sort, order } = req.query;

    // Build filter object
    const filter = {};

    // Search by name (case-insensitive)
    if (search) {
      // For CouchDB Mango queries, use $regex for case-insensitive search
      filter.name = { $regex: `(?i)${search}` };
    }

    // Filter by status
    if (status && ["available", "adopted", "maintenance"].includes(status)) {
      filter.status = status;
    }

    // Filter by adopter
    if (adoptedBy) {
      filter["adoptedBy.userId"] = adoptedBy;
    }

    // Build sort configuration
    let sortConfig = [{ name: "asc" }]; // Default sort
    if (sort === "name") {
      sortConfig = [{ name: order === "desc" ? "desc" : "asc" }];
    } else if (sort === "adoptedAt") {
      sortConfig = [{ updatedAt: order === "desc" ? "desc" : "asc" }];
    }

    // Query streets with filters
    const streets = await Street.find({
      ...filter,
      sort: sortConfig,
      skip,
      limit
    });

    // Populate adoptedBy information
    for (const street of streets) {
      if (street.adoptedBy && street.adoptedBy.userId) {
        await street.populate("adoptedBy");
      }
    }

    // Count total documents matching the filter
    const totalCount = await Street.countDocuments(filter);

    // Set X-Total-Count header for client-side pagination
    res.setHeader("X-Total-Count", totalCount);

    res.json(buildPaginatedResponse(streets, totalCount, page, limit));
  }),
);

// Get single street
router.get(
  "/:id",
  streetIdValidation,
  getCacheMiddleware(300), // Cache for 5 minutes
  asyncHandler(async (req, res) => {
    const street = await Street.findById(req.params.id);
    if (!street) {
      return res.status(404).json({ msg: "Street not found" });
    }
    
    // Populate adoptedBy information if exists
    if (street.adoptedBy && street.adoptedBy.userId) {
      await street.populate("adoptedBy");
    }
    
    res.json(street);
  }),
);

// Create a street
router.post(
  "/",
  auth,
  createStreetValidation,
  asyncHandler(async (req, res) => {
    const { name, location } = req.body;

    const street = await Street.create({
      name,
      location,
    });

    // Invalidate streets cache
    invalidateCacheByPattern('/api/streets');

    res.json(street);
  }),
);

// Adopt a street
router.put(
  "/adopt/:id",
  auth,
  streetIdValidation,
  asyncHandler(async (req, res) => {
    try {
      await couchdbService.initialize();
      
      const street = await Street.findById(req.params.id);
      if (!street) {
        return res.status(404).json({ msg: "Street not found" });
      }

      if (street.status === "adopted") {
        return res.status(400).json({ msg: "Street already adopted" });
      }

      // Check if user has already adopted this street
      const user = await User.findById(req.user.id);
      if (user.adoptedStreets.includes(req.params.id)) {
        return res
          .status(400)
          .json({ msg: "You have already adopted this street" });
      }

      // Get user details for embedding
      const userDetails = {
        userId: user._id,
        name: user.name,
        profilePicture: user.profilePicture || ''
      };

      // Update street
      street.adoptedBy = userDetails;
      street.status = "adopted";
      await street.save();

      // Update user's adoptedStreets array
      user.adoptedStreets.push(street._id);
      user.stats.streetsAdopted = user.adoptedStreets.length;
      await user.save();

      // Invalidate streets cache
      invalidateCacheByPattern('/api/streets');

      // Award points for street adoption using CouchDB service
      const updatedUser = await couchdbService.updateUserPoints(
        req.user.id,
        50,
        'Street adoption',
        {
          entityType: 'Street',
          entityId: street._id,
          entityName: street.name
        }
      );

      // Emit SSE event for street adoption
      const sse = req.app.get("sse");
      if (sse) {
        sse.broadcastToTopic("streets", "streetUpdate", {
          type: "street_adopted",
          streetId: street._id,
          userId: req.user.id,
        });
      }

      res.json({
        street,
        pointsAwarded: 50,
        newBalance: updatedUser.points,
        badgesEarned: [], // Badges are handled automatically in CouchDB service
      });
    } catch (err) {
      console.error("Error adopting street:", err.message);
      throw err;
    }
  }),
);

module.exports = router;
