package com.mvrent.carrental.controller;

import com.mvrent.carrental.model.*;
import com.mvrent.carrental.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/admin/reports")
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN') or hasAuthority('VIEW_REPORTS')")
public class AdminReportController {

    private final ReportService reportService;
    private final CarService carService;
    private final DriverService driverService;
    private final VendorService vendorService;
    private final ConfigService configService;
    private final ExcelService excelService;
    private final PdfService pdfService;

    /** Build a filter from raw query params, ignoring blanks (avoids empty-enum binding errors). */
    private BookingFilter parse(Map<String, String> p) {
        return new BookingFilter(
                date(p.get("from")), date(p.get("to")),
                lng(p.get("carId")), lng(p.get("driverId")), lng(p.get("vendorId")),
                blank(p.get("ownership")) ? null : CarOwnership.valueOf(p.get("ownership")),
                blank(p.get("status")) ? null : BookingStatus.valueOf(p.get("status")),
                lng(p.get("customerCategoryId")));
    }

    private void addLookups(Model model) {
        model.addAttribute("cars", carService.findAll());
        model.addAttribute("drivers", driverService.findAll());
        model.addAttribute("vendors", vendorService.findAll());
        model.addAttribute("customerCategories", configService.categoriesOfType(CategoryType.CUSTOMER));
        model.addAttribute("ownerships", CarOwnership.values());
        model.addAttribute("statuses", BookingStatus.values());
    }

    @GetMapping
    public String bookingsReport(@RequestParam Map<String, String> params, Model model) {
        BookingFilter f = parse(params);
        List<Booking> bookings = reportService.bookings(f);
        model.addAttribute("bookings", bookings);
        model.addAttribute("summary", reportService.summarize(bookings));
        model.addAttribute("p", params);   // echo filters back into the form + export links
        addLookups(model);
        return "admin/reports";
    }

    @GetMapping("/excel")
    public ResponseEntity<byte[]> bookingsExcel(@RequestParam Map<String, String> params) {
        List<Booking> bookings = reportService.bookings(parse(params));
        byte[] xlsx = excelService.bookingsWorkbook(bookings, reportService.summarize(bookings));
        return download(xlsx, AdminSettlementController.XLSX, "attachment", "bookings-report.xlsx");
    }

    @GetMapping("/pdf")
    public ResponseEntity<byte[]> bookingsPdf(@RequestParam Map<String, String> params) {
        List<Booking> bookings = reportService.bookings(parse(params));
        byte[] pdf = pdfService.render("pdf/report-bookings", Map.of(
                "bookings", bookings,
                "summary", reportService.summarize(bookings),
                "orgName", configService.getOrganization().getName()));
        return download(pdf, MediaType.APPLICATION_PDF, "inline", "bookings-report.pdf");
    }

    /* ---------- Vendor-wise ---------- */

    @GetMapping("/vendors")
    public String vendorReport(Model model) {
        model.addAttribute("rows", reportService.vendorReport());
        return "admin/report-vendors";
    }

    @GetMapping("/vendors/excel")
    public ResponseEntity<byte[]> vendorReportExcel() {
        return download(excelService.vendorReportWorkbook(reportService.vendorReport()),
                AdminSettlementController.XLSX, "attachment", "vendor-report.xlsx");
    }

    /* ---------- Driver-wise ---------- */

    @GetMapping("/drivers")
    public String driverReport(Model model) {
        model.addAttribute("rows", reportService.driverReport());
        return "admin/report-drivers";
    }

    @GetMapping("/drivers/excel")
    public ResponseEntity<byte[]> driverReportExcel() {
        return download(excelService.driverReportWorkbook(reportService.driverReport()),
                AdminSettlementController.XLSX, "attachment", "driver-report.xlsx");
    }

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

    private ResponseEntity<byte[]> download(byte[] body, MediaType type, String disposition, String filename) {
        return ResponseEntity.ok().contentType(type)
                .header(HttpHeaders.CONTENT_DISPOSITION, disposition + "; filename=\"" + filename + "\"")
                .body(body);
    }

    private static boolean blank(String s) { return s == null || s.isBlank(); }
    private static Long lng(String s) { return blank(s) ? null : Long.valueOf(s.trim()); }
    private static LocalDate date(String s) { return blank(s) ? null : LocalDate.parse(s.trim()); }
}
