package com.nebula.erp.purchase.controller;

import com.nebula.erp.purchase.document.DebitNoteSwagger;
import com.nebula.erp.purchase.model.DebitNote;
import com.nebula.erp.purchase.requestmodel.DebitRequest;
import com.nebula.erp.purchase.service.DebitService;
import com.nebula.erp.purchase.utility.ApiResponseStructure;
import com.nebula.erp.purchase.utility.CreateLogger;
import com.nebula.erp.purchase.utility.MoneyUtils;
import com.nebula.erp.purchase.utility.PermissionHelper;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/debit-notes")
@Tag(name = "Debit Note APIs", description = "API for managing Debit Note")
@DebitNoteSwagger.GlobalErrorResponse
public class DebitController {

    @Autowired
    private DebitService debitService;

    @Autowired
    private PermissionHelper permissionHelper;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/debit-notes";

    @DebitNoteSwagger.CreateDebitNoteOperation
    @PostMapping
    public ResponseEntity<ApiResponseStructure<DebitNote>> createDebit(@RequestBody DebitRequest debitRequest) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("create-purchase")) {
                createLogger.createLogger("error", path, "POST", "Forbidden: You do not have the required permission. Please contact the administration.", "validation");
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ApiResponseStructure<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            DebitNote debitNote = debitService.createDebit(debitRequest);
            ApiResponseStructure<DebitNote> response = new ApiResponseStructure<>("success",HttpStatus.CREATED.value(),"Debit note created successfully",debitNote);
            createLogger.createLogger("application", path, "POST", "Debit note created successfully", "");
            return ResponseEntity.status(HttpStatus.CREATED).body(response);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "POST", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @DebitNoteSwagger.GetDebitNoteByIdOperation
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getDebit(@PathVariable Long id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-purchase")) {
                createLogger.createLogger("error", path, "GET", "Forbidden: You do not have the required permission. Please contact the administration.", "validation");
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ApiResponseStructure<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            Optional<DebitNote> debitNoteOptional = debitService.getDebit(id);
            if (debitNoteOptional.isPresent()) {
                DebitNote debitNote = debitNoteOptional.get();

                // Create a map to hold sales data
                Map<String, Object> data = prepareDebitResponse(debitNote);

                // Define columns
                Map<String, String> debitColumns = new LinkedHashMap<>();
                debitColumns.put("id", "ID");
                debitColumns.put("debit_note_id", "DEBIT NOTE ID");
                debitColumns.put("invoice_id", "INVOICE ID");
                debitColumns.put("supplier_id", "SUPPLIER ID");
                debitColumns.put("date", "DATE");
                debitColumns.put("grn_id", "GRN ID");
                debitColumns.put("purchase_return_id", "PURCHASE RETURN ID");
                debitColumns.put("debit_amount", "DEBIT AMOUNT");
                debitColumns.put("refund_amount", "REFUND AMOUNT");
                debitColumns.put("discount_amount", "DISCOUNT AMOUNT");
                debitColumns.put("payment_method", "PAYMENT METHOD");
                debitColumns.put("reason", "REASON");
                debitColumns.put("created_by", "CREATED BY");
                debitColumns.put("created_at", "CREATED AT");

                // Add sales item columns to the response
                data.put("columns", debitColumns);

                ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success",HttpStatus.CREATED.value(),"Debit note retrieved successfully",data);
                createLogger.createLogger("application", path, "GET", "Debit note retrieved successfully", "");
                return ResponseEntity.ok(response);
            } else {
                createLogger.createLogger("error", path, "GET", "Purchase return not found", "runtime");
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ApiResponseStructure<>("error", HttpStatus.NOT_FOUND.value(), "Purchase return not found", null));
            }
        } catch (Exception e) {
            createLogger.createLogger("error", path, "GET", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @DebitNoteSwagger.GetAllDebitNotesOperation
    @GetMapping
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getAllDebitNotes(
            @RequestParam(value = "page", defaultValue = "1") int page,
            @RequestParam(value = "size", defaultValue = "10") int size,
            @RequestParam(value = "purchase_return_id", required = false) String purchase_return_id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-purchase")) {
                createLogger.createLogger("error", path, "GET", "Forbidden: You do not have the required permission. Please contact the administration.", "validation");
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ApiResponseStructure<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            Page<DebitNote> debitNotes = debitService.getAllDebitNotes(page, size, purchase_return_id);

            // Prepare pagination data
            Map<String, Object> pagination = new LinkedHashMap<>();
            pagination.put("current_page", debitNotes.getNumber() + 1);
            pagination.put("per_page", debitNotes.getSize());
            pagination.put("total", debitNotes.getTotalElements());
            pagination.put("last_page", debitNotes.getTotalPages());
            pagination.put("next_page_url", debitNotes.hasNext() ? "/api/debit-notes?page=" + (page + 1) + "&size=" + size : null);
            pagination.put("prev_page_url", debitNotes.hasPrevious() ? "/api/debit-notes?page=" + (page - 1) + "&size=" + size : null);

            // Define columns
            Map<String, String> debitColumns = new LinkedHashMap<>();
            debitColumns.put("id", "ID");
            debitColumns.put("debit_note_id", "DEBIT NOTE ID");
            debitColumns.put("invoice_id", "INVOICE ID");
            debitColumns.put("supplier_id", "SUPPLIER ID");
            debitColumns.put("date", "DATE");
            debitColumns.put("grn_id", "GRN ID");
            debitColumns.put("purchase_return_id", "PURCHASE RETURN ID");
            debitColumns.put("debit_amount", "DEBIT AMOUNT");
            debitColumns.put("refund_amount", "REFUND AMOUNT");
            debitColumns.put("discount_amount", "DISCOUNT AMOUNT");
            debitColumns.put("payment_method", "PAYMENT METHOD");
            debitColumns.put("reason", "REASON");
            debitColumns.put("created_by", "CREATED BY");
            debitColumns.put("created_at", "CREATED AT");

            List<Map<String, Object>> debitItems = debitNotes.getContent().stream()
                    .map(this::prepareDebitResponse)
                    .filter(Objects::nonNull)  // Exclude prescriptions with no items
                    .collect(Collectors.toList());

            // Prepare data for response
            Map<String, Object> data = new LinkedHashMap<>();
            data.put("pagination", pagination);
            data.put("items", debitItems);
            data.put("columns", debitColumns);

            // Create and return ApiResponse object
            ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success", HttpStatus.OK.value(), "Debit notes retrieved successfully", data);
            createLogger.createLogger("application", path, "GET", "Debit notes retrieved successfully", "");
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "GET", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    private Map<String, Object> prepareDebitResponse(DebitNote debitNote) {
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("id", debitNote.getId());
        data.put("debit_note_id", debitNote.getDebit_note_id());
        data.put("invoice_id", debitNote.getInvoice_id());
        data.put("supplier_id", debitNote.getSupplier_id());
        data.put("date", String.valueOf(debitNote.getDate()));
        data.put("grn_id", debitNote.getGrn_id());
        data.put("purchase_return_id", debitNote.getPurchase_return_id());
        data.put("debit_amount", MoneyUtils.truncateToTwoDecimals(debitNote.getDebit_amount()));
        data.put("refund_amount", MoneyUtils.truncateToTwoDecimals(debitNote.getRefund_amount()));
        data.put("discount_amount", MoneyUtils.truncateToTwoDecimals(debitNote.getDiscount_amount()));
        data.put("payment_method", debitNote.getPayment_method());
        data.put("reason", debitNote.getReason());
        data.put("created_by", debitNote.getCreated_by());
        data.put("created_at", String.valueOf(debitNote.getCreated_at()));
        return data;
    }

}