package com.mvrent.carrental.service;

import com.mvrent.carrental.model.Booking;
import com.mvrent.carrental.model.VendorSettlement;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.util.List;

import com.mvrent.carrental.service.ReportService.DriverReportRow;
import com.mvrent.carrental.service.ReportService.ReportSummary;
import com.mvrent.carrental.service.ReportService.VendorReportRow;

/** Builds .xlsx exports for vendor settlement statements. */
@Service
public class ExcelService {

    public byte[] settlementWorkbook(VendorSettlement s, List<Booking> trips) {
        try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            Sheet sheet = wb.createSheet("Settlement");

            CellStyle bold = wb.createCellStyle();
            Font f = wb.createFont();
            f.setBold(true);
            bold.setFont(f);

            int r = 0;
            r = kv(sheet, r, "Vendor", s.getVendor().getName(), bold);
            r = kv(sheet, r, "Period", s.getPeriodStart() + " to " + s.getPeriodEnd(), bold);
            r = kv(sheet, r, "Status", String.valueOf(s.getStatus()), bold);
            r = kv(sheet, r, "Trips", String.valueOf(s.getTripCount()), bold);
            r = kv(sheet, r, "Gross Revenue", money(s.getGrossRevenue()), bold);
            r = kv(sheet, r, "Commission", money(s.getCommissionAmount()), bold);
            r = kv(sheet, r, "Vendor Driver Charges", money(s.getDriverCharges()), bold);
            r = kv(sheet, r, "Net Payable", money(s.getNetPayable()), bold);
            r++;

            // Trip line items
            Row head = sheet.createRow(r++);
            String[] cols = {"Booking", "Car", "Pickup", "Return", "Vehicle Charge", "Commission", "Driver Charge", "Total"};
            for (int i = 0; i < cols.length; i++) {
                Cell c = head.createCell(i);
                c.setCellValue(cols[i]);
                c.setCellStyle(bold);
            }
            for (Booking b : trips) {
                Row row = sheet.createRow(r++);
                row.createCell(0).setCellValue("#" + b.getId());
                row.createCell(1).setCellValue(b.getCar().getMake() + " " + b.getCar().getModel());
                row.createCell(2).setCellValue(String.valueOf(b.getPickupDate()));
                row.createCell(3).setCellValue(String.valueOf(b.getReturnDate()));
                row.createCell(4).setCellValue(dbl(b.getVehicleCharge()));
                row.createCell(5).setCellValue(dbl(b.getCommissionAmount()));
                row.createCell(6).setCellValue(dbl(b.getDriverCharge()));
                row.createCell(7).setCellValue(dbl(b.getTotalAmount()));
            }
            for (int i = 0; i < cols.length; i++) sheet.autoSizeColumn(i);

            wb.write(os);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to build Excel: " + e.getMessage(), e);
        }
    }

    public byte[] bookingsWorkbook(List<Booking> bookings, ReportSummary summary) {
        try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            Sheet sheet = wb.createSheet("Bookings");
            CellStyle bold = boldStyle(wb);

            String[] cols = {"ID", "Customer", "Car", "Driver", "Owner", "Pickup", "Return",
                    "Vehicle", "Driver Chg", "Tax", "Commission", "Total", "Status"};
            header(sheet, cols, bold);
            int r = 1;
            for (Booking b : bookings) {
                Row row = sheet.createRow(r++);
                row.createCell(0).setCellValue(b.getId());
                row.createCell(1).setCellValue(b.getUser().getFullName());
                row.createCell(2).setCellValue(b.getCar().getMake() + " " + b.getCar().getModel());
                row.createCell(3).setCellValue(b.isWithDriver() && b.getDriver() != null ? b.getDriver().getName() : "Self-drive");
                row.createCell(4).setCellValue(String.valueOf(b.getRevenueOwner()));
                row.createCell(5).setCellValue(String.valueOf(b.getPickupDate()));
                row.createCell(6).setCellValue(String.valueOf(b.getReturnDate()));
                row.createCell(7).setCellValue(dbl(b.getVehicleCharge()));
                row.createCell(8).setCellValue(dbl(b.getDriverCharge()));
                row.createCell(9).setCellValue(dbl(b.getTaxAmount()));
                row.createCell(10).setCellValue(dbl(b.getCommissionAmount()));
                row.createCell(11).setCellValue(dbl(b.getTotalAmount()));
                row.createCell(12).setCellValue(String.valueOf(b.getStatus()));
            }
            r++;
            kv(sheet, r++, "Bookings", String.valueOf(summary.count()), bold);
            kv(sheet, r++, "Gross (vehicle)", money(summary.gross()), bold);
            kv(sheet, r++, "Driver charges", money(summary.driverCharges()), bold);
            kv(sheet, r++, "Tax", money(summary.tax()), bold);
            kv(sheet, r++, "Commission", money(summary.commission()), bold);
            kv(sheet, r++, "Total", money(summary.total()), bold);
            for (int i = 0; i < cols.length; i++) sheet.autoSizeColumn(i);
            wb.write(os);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to build Excel: " + e.getMessage(), e);
        }
    }

    public byte[] vendorReportWorkbook(List<VendorReportRow> rows) {
        try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            Sheet sheet = wb.createSheet("Vendor Revenue");
            CellStyle bold = boldStyle(wb);
            String[] cols = {"Vendor", "Trips", "Gross", "Commission", "Net Payable"};
            header(sheet, cols, bold);
            int r = 1;
            for (VendorReportRow row : rows) {
                Row x = sheet.createRow(r++);
                x.createCell(0).setCellValue(row.vendor());
                x.createCell(1).setCellValue(row.trips());
                x.createCell(2).setCellValue(dbl(row.gross()));
                x.createCell(3).setCellValue(dbl(row.commission()));
                x.createCell(4).setCellValue(dbl(row.net()));
            }
            for (int i = 0; i < cols.length; i++) sheet.autoSizeColumn(i);
            wb.write(os);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to build Excel: " + e.getMessage(), e);
        }
    }

    public byte[] driverReportWorkbook(List<DriverReportRow> rows) {
        try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            Sheet sheet = wb.createSheet("Driver Report");
            CellStyle bold = boldStyle(wb);
            String[] cols = {"Driver", "Category", "Trips", "Driver Charges"};
            header(sheet, cols, bold);
            int r = 1;
            for (DriverReportRow row : rows) {
                Row x = sheet.createRow(r++);
                x.createCell(0).setCellValue(row.driver());
                x.createCell(1).setCellValue(row.category());
                x.createCell(2).setCellValue(row.trips());
                x.createCell(3).setCellValue(dbl(row.charges()));
            }
            for (int i = 0; i < cols.length; i++) sheet.autoSizeColumn(i);
            wb.write(os);
            return os.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("Failed to build Excel: " + e.getMessage(), e);
        }
    }

    private CellStyle boldStyle(Workbook wb) {
        CellStyle bold = wb.createCellStyle();
        Font f = wb.createFont();
        f.setBold(true);
        bold.setFont(f);
        return bold;
    }

    private void header(Sheet sheet, String[] cols, CellStyle bold) {
        Row head = sheet.createRow(0);
        for (int i = 0; i < cols.length; i++) {
            Cell c = head.createCell(i);
            c.setCellValue(cols[i]);
            c.setCellStyle(bold);
        }
    }

    private int kv(Sheet sheet, int r, String key, String val, CellStyle bold) {
        Row row = sheet.createRow(r);
        Cell k = row.createCell(0);
        k.setCellValue(key);
        k.setCellStyle(bold);
        row.createCell(1).setCellValue(val);
        return r + 1;
    }

    private static String money(BigDecimal v) {
        return v == null ? "0.00" : v.toPlainString();
    }

    private static double dbl(BigDecimal v) {
        return v == null ? 0d : v.doubleValue();
    }
}
