package com.mvrent.carrental.controller;

import com.mvrent.carrental.model.Car;
import com.mvrent.carrental.model.CarType;
import com.mvrent.carrental.model.Transmission;
import com.mvrent.carrental.service.CarService;
import com.mvrent.carrental.service.DriverService;
import com.mvrent.carrental.service.ReviewService;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Controller
@RequestMapping("/cars")
@RequiredArgsConstructor
public class CarController {

    private final CarService carService;
    private final DriverService driverService;
    private final ReviewService reviewService;

    @GetMapping
    public String list(@RequestParam(required = false)
                       @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate pickup,
                       @RequestParam(required = false)
                       @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate ret,
                       @RequestParam(required = false) CarType type,
                       @RequestParam(required = false) Integer minSeats,
                       @RequestParam(required = false) Transmission transmission,
                       @RequestParam(required = false) BigDecimal maxPrice,
                       @RequestParam(required = false) Boolean withDriver,
                       @RequestParam(required = false) String pickupLocation,
                       @RequestParam(required = false) String dropLocation,
                       @RequestParam(required = false) String promo,
                       Model model) {

        List<Car> cars;
        Long days = null;
        if (pickup != null && ret != null && ret.isAfter(pickup)) {
            cars = carService.findAvailableBetween(pickup, ret);
            days = Math.max(1, ChronoUnit.DAYS.between(pickup, ret));
        } else {
            cars = carService.findAvailable();
        }

        // In-memory refine by the optional attribute filters.
        cars = cars.stream()
                .filter(c -> type == null || c.getType() == type)
                .filter(c -> minSeats == null || c.getSeats() >= minSeats)
                .filter(c -> transmission == null || c.getTransmission() == transmission)
                .filter(c -> maxPrice == null || c.getPricePerDay().compareTo(maxPrice) <= 0)
                .toList();

        model.addAttribute("cars", cars);
        model.addAttribute("days", days);
        model.addAttribute("availableDrivers", driverService.findAvailable().size());
        // echo filters back into the form
        model.addAttribute("pickup", pickup);
        model.addAttribute("ret", ret);
        model.addAttribute("type", type);
        model.addAttribute("minSeats", minSeats);
        model.addAttribute("transmission", transmission);
        model.addAttribute("maxPrice", maxPrice);
        model.addAttribute("withDriver", withDriver);
        model.addAttribute("pickupLocation", pickupLocation);
        model.addAttribute("dropLocation", dropLocation);
        model.addAttribute("promo", promo);
        model.addAttribute("carTypes", CarType.values());
        model.addAttribute("transmissions", Transmission.values());
        return "cars/list";
    }

    @GetMapping("/{id}")
    public String detail(@PathVariable Long id,
                         @RequestParam(required = false)
                         @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate pickup,
                         @RequestParam(required = false)
                         @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate ret,
                         Model model) {
        model.addAttribute("car", carService.findById(id));
        Long days = (pickup != null && ret != null && ret.isAfter(pickup))
                ? Math.max(1, ChronoUnit.DAYS.between(pickup, ret)) : null;
        model.addAttribute("days", days);
        model.addAttribute("pickup", pickup);
        model.addAttribute("ret", ret);
        model.addAttribute("availableDrivers", driverService.findAvailable().size());
        model.addAttribute("reviews", reviewService.approvedForCar(id));
        model.addAttribute("avgRating", reviewService.averageForCar(id));
        model.addAttribute("reviewCount", reviewService.countForCar(id));
        return "cars/detail";
    }
}
