import { Response } from "express";
import { Types } from "mongoose";
import Trip from "../../models/TripModel";
import ResponseUtil from "../../utils/Response/responseUtils";
import { STATUS_CODES } from "../../constants/statusCodes";
import { CustomRequest } from "../../interfaces/auth";
import { adminTripPatchSchema } from "../../validators/adminValidators";

export const listTripsAdmin = async (req: CustomRequest, res: Response) => {
  try {
    const page = Math.max(parseInt((req.query.page as string) || "1", 10), 1);
    const limit = Math.min(
      Math.max(parseInt((req.query.limit as string) || "20", 10), 1),
      100
    );
    const skip = (page - 1) * limit;
    const status = req.query.status as string | undefined;
    const userId = req.query.userId as string | undefined;
    const filter: Record<string, unknown> = { isDeleted: false };
    if (status && ["planned", "in-progress", "completed", "cancelled"].includes(status)) {
      filter.status = status;
    }
    if (userId && Types.ObjectId.isValid(userId)) {
      filter.userId = new Types.ObjectId(userId);
    }

    const [trips, total] = await Promise.all([
      Trip.find(filter)
        .sort({ scheduledDate: -1 })
        .skip(skip)
        .limit(limit)
        .populate("userId", "email fullName")
        .populate("vehicleId", "name vehicleModel currentMPG")
        .lean(),
      Trip.countDocuments(filter),
    ]);

    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      { total, page, limit, totalPages: Math.ceil(total / limit), trips },
      "Trips"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

export const getTripAdmin = async (req: CustomRequest, res: Response) => {
  try {
    const { id } = req.params;
    if (!Types.ObjectId.isValid(id)) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        "Invalid id"
      );
    }
    const trip = await Trip.findById(id)
      .populate("userId", "email fullName phone")
      .populate("vehicleId")
      .lean();
    if (!trip) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        "Trip not found"
      );
    }
    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      { trip },
      "Trip detail"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

export const updateTripAdmin = async (req: CustomRequest, res: Response) => {
  try {
    const { id } = req.params;
    if (!Types.ObjectId.isValid(id)) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        "Invalid id"
      );
    }
    const body = await adminTripPatchSchema.parseAsync(req.body);
    const trip = await Trip.findByIdAndUpdate(id, body, { new: true })
      .populate("userId", "email fullName")
      .populate("vehicleId", "name vehicleModel")
      .lean();
    if (!trip) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        "Trip not found"
      );
    }
    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      { trip },
      "Trip updated"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

export const deleteTripAdmin = async (req: CustomRequest, res: Response) => {
  try {
    const { id } = req.params;
    if (!Types.ObjectId.isValid(id)) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        "Invalid id"
      );
    }
    const trip = await Trip.findByIdAndUpdate(
      id,
      { isDeleted: true },
      { new: true }
    ).lean();
    if (!trip) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        "Trip not found"
      );
    }
    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      {},
      "Trip deleted (soft)"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

/** Route + schedule context; live GPS is not persisted in Trip schema. */
export const getTripTrackingAdmin = async (
  req: CustomRequest,
  res: Response
) => {
  try {
    const { id } = req.params;
    if (!Types.ObjectId.isValid(id)) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.BAD_REQUEST,
        "Invalid id"
      );
    }
    const trip = await Trip.findById(id)
      .populate("userId", "email fullName")
      .populate("vehicleId", "name vehicleModel smartcarVehicleId")
      .lean();
    if (!trip) {
      return ResponseUtil.errorResponse(
        res,
        STATUS_CODES.NOT_FOUND,
        "Trip not found"
      );
    }

    const vehicle = trip.vehicleId as unknown as {
      smartcarVehicleId?: string;
    };

    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      {
        tripId: trip._id,
        status: trip.status,
        scheduledDate: trip.scheduledDate,
        updatedAt: trip.updatedAt,
        route: {
          start: trip.startPoint,
          end: trip.endPoint,
          distanceKm: trip.calculatedDistance,
          metrics: trip.calculatedMetrics,
        },
        user: trip.userId,
        vehicleSummary: trip.vehicleId,
        liveTrackingNote:
          "Stored trips include planned start/end only. Integrate Smartcar or device telemetry for live coordinates.",
        smartcarVehicleId: vehicle?.smartcarVehicleId ?? null,
      },
      "Trip tracking context"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

export const listLowFuelTripRemindersAdmin = async (
  req: CustomRequest,
  res: Response
) => {
  try {
    const filter = {
      isDeleted: false,
      lowFuelReminder: { $exists: true, $ne: "" },
      status: { $in: ["planned", "in-progress"] },
    };
    const trips = await Trip.find(filter)
      .sort({ updatedAt: -1 })
      .limit(200)
      .populate("userId", "email fullName")
      .populate("vehicleId", "name")
      .lean();

    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      {
        count: trips.length,
        trips,
        note: "Low-fuel strings are stored per trip; push notifications are not logged here unless you add a Notification model.",
      },
      "Trips with active low-fuel reminder text"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};

export const upcomingTripsAdmin = async (req: CustomRequest, res: Response) => {
  try {
    const now = new Date();
    const filter = {
      isDeleted: false,
      scheduledDate: { $gte: now },
      status: { $in: ["planned", "in-progress"] },
    };
    const trips = await Trip.find(filter)
      .sort({ scheduledDate: 1 })
      .limit(100)
      .populate("userId", "email fullName")
      .populate("vehicleId", "name")
      .lean();

    return ResponseUtil.successResponse(
      res,
      STATUS_CODES.SUCCESS,
      { count: trips.length, trips },
      "Upcoming trips"
    );
  } catch (e) {
    ResponseUtil.handleError(res, e);
  }
};
