package com.mvrent.carrental.controller;

import com.mvrent.carrental.model.Booking;
import com.mvrent.carrental.model.BookingStatus;
import com.mvrent.carrental.model.RentalUnit;
import com.mvrent.carrental.model.User;
import com.mvrent.carrental.service.BookingService;
import com.mvrent.carrental.service.PaymentService;
import com.mvrent.carrental.service.UserService;
import com.mvrent.carrental.web.AdminBookingForm;
import com.mvrent.carrental.web.BookingDto;
import com.mvrent.carrental.web.PaymentDto;
import com.mvrent.carrental.web.PaymentForm;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/** JSON API backing the AJAX Manage Bookings screen (inline status + counter bookings). */
@RestController
@RequestMapping("/admin/api/bookings")
@RequiredArgsConstructor
@PreAuthorize("hasRole('ADMIN') or hasAuthority('MANAGE_BOOKINGS')")
public class AdminBookingApiController {

    private final BookingService bookingService;
    private final UserService userService;
    private final PaymentService paymentService;

    @GetMapping
    public List<BookingDto> list() {
        Map<Long, BigDecimal> paid = paymentService.paidByBooking();
        return bookingService.findAll().stream()
                .map(b -> BookingDto.from(b, paid.get(b.getId())))
                .toList();
    }

    /* ---------- Payments ---------- */

    @GetMapping("/{id}/payments")
    public Map<String, Object> payments(@PathVariable Long id) {
        Booking b = bookingService.findById(id);
        BigDecimal total = b.getTotalAmount() != null ? b.getTotalAmount() : BigDecimal.ZERO;
        BigDecimal paid = paymentService.totalPaid(id);
        return Map.of(
                "total", total,
                "paid", paid,
                "balance", total.subtract(paid),
                "payments", paymentService.forBooking(id).stream().map(PaymentDto::from).toList()
        );
    }

    @PostMapping("/{id}/payments")
    public ResponseEntity<?> addPayment(@PathVariable Long id, @RequestBody PaymentForm f) {
        try {
            paymentService.record(id, f.amount(), f.method(), f.reference(), f.paidAt(), f.notes());
            return ResponseEntity.ok(Map.of("ok", true));
        } catch (IllegalArgumentException ex) {
            return bad(ex.getMessage());
        }
    }

    @PostMapping("/payments/{paymentId}/delete")
    public ResponseEntity<?> deletePayment(@PathVariable Long paymentId) {
        paymentService.delete(paymentId);
        return ResponseEntity.ok(Map.of("ok", true));
    }

    @PostMapping("/{id}/status")
    public ResponseEntity<?> updateStatus(@PathVariable Long id, @RequestParam BookingStatus status) {
        bookingService.updateStatus(id, status);
        return ResponseEntity.ok(Map.of("ok", true, "id", id, "status", status.name()));
    }

    /** Admin creates a booking on behalf of a customer (counter / phone booking). */
    @PostMapping
    public ResponseEntity<?> create(@RequestBody AdminBookingForm f) {
        if (f.carId() == null) return bad("Please select a car");
        if (f.pickupDate() == null || f.returnDate() == null) return bad("Pickup and return dates are required");
        if (isBlank(f.pickupLocation())) return bad("Pickup location is required");
        if (isBlank(f.dropLocation())) return bad("Drop location is required");

        // Resolve customer: an existing one, or create a walk-in record.
        User customer;
        try {
            if (f.customerId() != null) {
                customer = userService.findById(f.customerId());
            } else if (!isBlank(f.customerName())) {
                customer = userService.createWalkInCustomer(f.customerName(), f.customerPhone(), f.customerEmail());
            } else {
                return bad("Select a customer or enter a walk-in customer name");
            }
        } catch (IllegalArgumentException ex) {
            return bad(ex.getMessage());
        }

        Booking form = new Booking();
        form.setPickupDate(f.pickupDate());
        form.setReturnDate(f.returnDate());
        form.setPickupLocation(f.pickupLocation().trim());
        form.setDropLocation(f.dropLocation().trim());
        form.setRentalUnit(f.rentalUnit() != null ? f.rentalUnit() : RentalUnit.DAY);
        form.setWithDriver(f.withDriver());

        try {
            Booking saved = bookingService.createBooking(customer, f.carId(), form, f.driverId());
            return ResponseEntity.ok(Map.of("ok", true, "id", saved.getId()));
        } catch (IllegalArgumentException | IllegalStateException ex) {
            return bad(ex.getMessage());
        }
    }

    private static boolean isBlank(String s) { return s == null || s.trim().isEmpty(); }

    private static ResponseEntity<Map<String, Object>> bad(String msg) {
        return ResponseEntity.badRequest().body(Map.of("ok", false, "message", msg == null ? "Could not create booking" : msg));
    }
}
