package com.mvrent.carrental.controller;

import com.mvrent.carrental.model.BookingStatus;
import com.mvrent.carrental.model.Car;
import com.mvrent.carrental.model.CarDocumentType;
import com.mvrent.carrental.model.Invoice;
import com.mvrent.carrental.service.BookingService;
import com.mvrent.carrental.service.CarService;
import com.mvrent.carrental.service.ConfigService;
import com.mvrent.carrental.service.DashboardService;
import com.mvrent.carrental.service.DriverService;
import com.mvrent.carrental.service.FileStorageService;
import com.mvrent.carrental.service.PaymentService;
import com.mvrent.carrental.service.UserService;
import com.mvrent.carrental.service.PdfService;
import com.mvrent.carrental.service.VendorService;
import jakarta.validation.Valid;
import org.springframework.web.multipart.MultipartFile;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Controller
@RequestMapping("/admin")
@RequiredArgsConstructor
public class AdminController {

    private final CarService carService;
    private final BookingService bookingService;
    private final VendorService vendorService;
    private final PdfService pdfService;
    private final ConfigService configService;
    private final FileStorageService fileStorage;
    private final DashboardService dashboardService;
    private final DriverService driverService;
    private final UserService userService;
    private final PaymentService paymentService;

    @GetMapping
    public String dashboard(Model model) {
        model.addAttribute("d", dashboardService.build());
        return "admin/dashboard";
    }

    /* ---------- Cars ---------- */

    @GetMapping("/cars")
    public String cars(Model model) {
        model.addAttribute("cars", carService.findAll());
        model.addAttribute("vendors", vendorService.findActive());
        return "admin/cars";
    }

    @GetMapping("/cars/new")
    public String newCar(Model model) {
        if (!model.containsAttribute("car")) {
            model.addAttribute("car", new Car());
        }
        model.addAttribute("vendors", vendorService.findActive());
        return "admin/car-form";
    }

    @PostMapping("/cars")
    public String saveCar(@Valid @ModelAttribute("car") Car car,
                          BindingResult result,
                          @RequestParam(name = "featureTagsCsv", required = false) String featureTagsCsv,
                          @RequestParam(name = "vendorId", required = false) Long vendorId,
                          Model model,
                          RedirectAttributes ra) {
        if (result.hasErrors()) {
            model.addAttribute("vendors", vendorService.findActive());
            return "admin/car-form";
        }
        carService.saveFromForm(car, parseTags(featureTagsCsv), vendorId);
        ra.addFlashAttribute("success", "Car saved");
        return "redirect:/admin/cars";
    }

    @GetMapping("/cars/{id}/edit")
    public String editCar(@PathVariable Long id, Model model) {
        model.addAttribute("car", carService.findById(id));
        model.addAttribute("vendors", vendorService.findActive());
        return "admin/car-form";
    }

    @PostMapping("/cars/{id}/delete")
    public String deleteCar(@PathVariable Long id, RedirectAttributes ra) {
        carService.delete(id);
        ra.addFlashAttribute("success", "Car deleted");
        return "redirect:/admin/cars";
    }

    /* ---------- Car documents ---------- */

    @PostMapping("/cars/{id}/documents")
    public String addDocument(@PathVariable Long id,
                              @RequestParam CarDocumentType docType,
                              @RequestParam(required = false) String fileUrl,
                              @RequestParam(required = false) MultipartFile file,
                              @RequestParam(required = false)
                              @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate issuedDate,
                              @RequestParam(required = false)
                              @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate expiryDate,
                              RedirectAttributes ra) {
        String stored = fileStorage.store(file);
        carService.addDocument(id, docType, stored != null ? stored : fileUrl, issuedDate, expiryDate);
        ra.addFlashAttribute("success", docType + " document added");
        return "redirect:/admin/cars/" + id + "/edit";
    }

    @PostMapping("/cars/{id}/documents/{docId}/delete")
    public String deleteDocument(@PathVariable Long id, @PathVariable Long docId,
                                 RedirectAttributes ra) {
        carService.deleteDocument(docId);
        ra.addFlashAttribute("success", "Document removed");
        return "redirect:/admin/cars/" + id + "/edit";
    }

    /* ---------- Car photos ---------- */

    @PostMapping("/cars/{id}/photos")
    public String addPhoto(@PathVariable Long id,
                           @RequestParam(required = false) String url,
                           @RequestParam(required = false) MultipartFile file,
                           @RequestParam(defaultValue = "0") int sortOrder,
                           RedirectAttributes ra) {
        String stored = fileStorage.store(file);
        String finalUrl = stored != null ? stored : url;
        if (finalUrl == null || finalUrl.isBlank()) {
            ra.addFlashAttribute("error", "Provide a photo file or URL");
        } else {
            carService.addPhoto(id, finalUrl, sortOrder);
            ra.addFlashAttribute("success", "Photo added");
        }
        return "redirect:/admin/cars/" + id + "/edit";
    }

    @PostMapping("/cars/{id}/photos/{photoId}/delete")
    public String deletePhoto(@PathVariable Long id, @PathVariable Long photoId,
                              RedirectAttributes ra) {
        carService.deletePhoto(photoId);
        ra.addFlashAttribute("success", "Photo removed");
        return "redirect:/admin/cars/" + id + "/edit";
    }

    /* ---------- Bookings ---------- */

    @GetMapping("/bookings")
    public String bookings(Model model) {
        model.addAttribute("bookings", bookingService.findAll());
        model.addAttribute("customers", userService.findCustomers());
        model.addAttribute("availableCars", carService.findAvailable());
        model.addAttribute("availableDrivers", driverService.findAvailable());
        return "admin/bookings";
    }

    @PostMapping("/bookings/{id}/status")
    public String updateBookingStatus(@PathVariable Long id,
                                      @RequestParam BookingStatus status,
                                      RedirectAttributes ra) {
        bookingService.updateStatus(id, status);
        ra.addFlashAttribute("success", "Booking #" + id + " set to " + status);
        return "redirect:/admin/bookings";
    }

    @GetMapping("/bookings/{id}/invoice")
    public String invoice(@PathVariable Long id, Model model) {
        var booking = bookingService.findById(id);
        java.math.BigDecimal paid = paymentService.totalPaid(id);
        java.math.BigDecimal total = booking.getTotalAmount() != null ? booking.getTotalAmount() : java.math.BigDecimal.ZERO;
        model.addAttribute("booking", booking);
        model.addAttribute("invoice", bookingService.invoiceFor(id));
        model.addAttribute("payments", paymentService.forBooking(id));
        model.addAttribute("amountPaid", paid);
        model.addAttribute("balance", total.subtract(paid));
        model.addAttribute("pdfUrl", "/admin/bookings/" + id + "/invoice/pdf");
        return "bookings/invoice";
    }

    @GetMapping("/bookings/{id}/invoice/pdf")
    public ResponseEntity<byte[]> invoicePdf(@PathVariable Long id) {
        Invoice invoice = bookingService.invoiceFor(id);
        byte[] pdf = pdfService.render("pdf/invoice", Map.of(
                "booking", bookingService.findById(id), "invoice", invoice,
                "orgName", configService.getOrganization().getName()));
        return ResponseEntity.ok().contentType(MediaType.APPLICATION_PDF)
                .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + invoice.getInvoiceNumber() + ".pdf\"")
                .body(pdf);
    }

    /* ---------- helpers ---------- */

    private Set<String> parseTags(String csv) {
        if (csv == null || csv.isBlank()) return new LinkedHashSet<>();
        return Arrays.stream(csv.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toCollection(LinkedHashSet::new));
    }
}
