/*
 * File: src/main/java/purchase/controller/SupplierController.java
 * Description: This controller provides API endpoints for managing suppliers in the ERP system.
 * It includes operations to create, retrieve, update, and delete suppliers, with safeguards for
 * dependencies like purchases and GRNs to prevent unintended deletions. The controller also
 * includes Swagger documentation for each endpoint for better API visibility.
*/

package com.nebula.erp.purchase.controller;

import com.nebula.erp.purchase.document.SupplierSwagger;
import com.nebula.erp.purchase.model.Supplier;
import com.nebula.erp.purchase.requestmodel.SupplierRequest;
import com.nebula.erp.purchase.service.SupplierService;
import com.nebula.erp.purchase.utility.*;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/suppliers")
@Tag(name = "Supplier APIs", description = "API for managing Suppliers")
@SupplierSwagger.GlobalErrorResponse
public class SupplierController {

    @Autowired
    private SupplierService supplierService;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private PermissionHelper permissionHelper;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/suppliers";

    @SupplierSwagger.CreateSupplierOperation
    @PostMapping
    public ResponseEntity<ApiResponseStructure<Supplier>> createSupplier(@RequestBody SupplierRequest supplierRequest) {
        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));
            }

            Supplier createdSupplier = supplierService.createSupplier(supplierRequest);
            ApiResponseStructure<Supplier> response = new ApiResponseStructure<>("success", HttpStatus.CREATED.value(),
                    "Supplier created successfully", createdSupplier);
            createLogger.createLogger("application", path, "POST", "Supplier 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));
        }
    }

    @SupplierSwagger.GetSupplierByIdOperation
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getSupplierById(@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));
            }

            // Fetch tenant name from headers
            String tenantName = jwtRequestUtils.getTenantName();

            Optional<Supplier> supplier = supplierService.getSupplierById(id);
            if (supplier.isPresent()) {
                Supplier supplierData = supplier.get();

                // Check if the tenant name matches
                if (!supplierData.getTenant().equals(tenantName)) {
                    createLogger.createLogger("error", path, "GET",
                            "Unauthorized to view this supplier; tenant mismatch", "validation");
                    return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new ApiResponseStructure<>("error",
                            HttpStatus.FORBIDDEN.value(), "Unauthorized to view this supplier; tenant mismatch", null));
                }

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

                // Define columns for supplier
                Map<String, String> columns = new LinkedHashMap<>();
                columns.put("id", "ID");
                columns.put("supplier_id", "SUPPLIER ID");
                columns.put("supplier_name", "SUPPLIER NAME");
                columns.put("contact_person", "CONTACT PERSON");
                columns.put("phone_number", "PHONE NUMBER");
                columns.put("email_address", "EMAIL ADDRESS");
                columns.put("address", "ADDRESS");
                columns.put("city", "CITY");
                columns.put("state_province", "STATE/PROVINCE");
                columns.put("zip_postal_code", "ZIP/POSTAL CODE");
                columns.put("country", "COUNTRY");
                columns.put("website", "WEBSITE");
                columns.put("supplier_type", "SUPPLIER TYPE");
                columns.put("notes", "NOTES");
                columns.put("created_by", "CREATED BY");
                columns.put("tenant", "TENANT");
                columns.put("created_at", "CREATED AT");
                data.put("columns", columns);

                ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success",
                        HttpStatus.OK.value(), "Supplier retrieved successfully", data);
                createLogger.createLogger("application", path, "GET", "Supplier retrieved successfully", "");
                return ResponseEntity.ok(response);
            } else {
                createLogger.createLogger("error", path, "GET", "Supplier not found", "runtime");
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(
                        new ApiResponseStructure<>("error", HttpStatus.NOT_FOUND.value(), "Supplier 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));
        }
    }

    // Get suppliers count
    @GetMapping("/count")
    public ResponseEntity<ApiResponseStructure<Integer>> getSuppliersCount(
            @RequestParam(value = "tenant", required = true) String tenant_name) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-sales")) {
                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));
            }
            Integer suppliersCount = supplierService.getSuppliersCount(tenant_name);
            ApiResponseStructure<Integer> response = new ApiResponseStructure<>("success", HttpStatus.OK.value(),
                    "Suppliers count retrieved successfully", suppliersCount);
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SupplierSwagger.GetAllSuppliersOperation
    @GetMapping
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getAllSuppliers(
            @RequestParam(value = "page", defaultValue = "1") int page,
            @RequestParam(value = "size", defaultValue = "10") int size,
            @RequestParam(value = "search", required = false) String search) {
        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<Supplier> supplierPage = supplierService.getAllSuppliers(page, size, search);

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

            // Define columns for supplier
            Map<String, String> columns = new LinkedHashMap<>();
            columns.put("id", "ID");
            columns.put("supplier_id", "SUPPLIER ID");
            columns.put("supplier_name", "SUPPLIER NAME");
            columns.put("contact_person", "CONTACT PERSON");
            columns.put("phone_number", "PHONE NUMBER");
            columns.put("email_address", "EMAIL ADDRESS");
            columns.put("address", "ADDRESS");
            columns.put("city", "CITY");
            columns.put("state_province", "STATE/PROVINCE");
            columns.put("zip_postal_code", "ZIP/POSTAL CODE");
            columns.put("country", "COUNTRY");
            columns.put("website", "WEBSITE");
            columns.put("supplier_type", "SUPPLIER TYPE");
            columns.put("notes", "NOTES");
            columns.put("created_by", "CREATED BY");
            columns.put("tenant", "TENANT");
            columns.put("created_at", "CREATED AT");

            // Prepare data for response
            List<Map<String, Object>> supplierItems = supplierPage.getContent().stream()
                    .map(this::prepareSupplierResponse)
                    .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", supplierItems);
            data.put("columns", columns);

            // Create and return ApiResponseStructure object
            ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success",
                    HttpStatus.OK.value(), "Suppliers retrieved successfully", data);
            createLogger.createLogger("application", path, "GET", "Suppliers 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));
        }
    }

    @SupplierSwagger.UpdateSupplierOperation
    @PutMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Supplier>> updateSupplier(@PathVariable Long id,
            @RequestBody SupplierRequest supplierRequest) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("update-purchase")) {
                createLogger.createLogger("error", path, "PUT",
                        "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));
            }

            Supplier updatedSupplier = supplierService.updateSupplier(id, supplierRequest);
            ApiResponseStructure<Supplier> response = new ApiResponseStructure<>("success", HttpStatus.OK.value(),
                    "Supplier updated successfully", updatedSupplier);
            createLogger.createLogger("application", path, "PUT", "Supplier updated successfully", "");
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "PUT", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @SupplierSwagger.DeleteSupplierOperation
    @DeleteMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Void>> deleteSupplier(@PathVariable Long id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("delete-purchase")) {
                createLogger.createLogger("error", path, "DELETE",
                        "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));
            }

            // Check if the supplier is associated with any purchases or GRNs
            boolean isAssociatedWithPurchase = supplierService.existsByPurchases(id);
            boolean isAssociatedWithGrn = supplierService.existsByGrns(id);

            if (isAssociatedWithPurchase) {
                createLogger.createLogger("error", path, "DELETE",
                        "Cannot delete supplier. Supplier is associated with existing purchases", "conflict");
                return ResponseEntity.status(HttpStatus.CONFLICT)
                        .body(new ApiResponseStructure<>("error", HttpStatus.CONFLICT.value(),
                                "Cannot delete supplier. Supplier is associated with existing purchases", null));
            }
            if (isAssociatedWithGrn) {
                createLogger.createLogger("error", path, "DELETE",
                        "Cannot delete supplier. Supplier is associated with existing GRNs.", "conflict");
                return ResponseEntity.status(HttpStatus.CONFLICT)
                        .body(new ApiResponseStructure<>("error", HttpStatus.CONFLICT.value(),
                                "Cannot delete supplier. Supplier is associated with existing GRNs.", null));
            }

            supplierService.deleteSupplier(id);
            ApiResponseStructure<Void> response = new ApiResponseStructure<>("success", HttpStatus.OK.value(),
                    "Supplier deleted successfully", null);
            createLogger.createLogger("application", path, "DELETE", "Supplier deleted successfully", "");
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "DELETE", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    // Helper method to prepare response data for a supplier
    private Map<String, Object> prepareSupplierResponse(Supplier supplierData) {
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("id", supplierData.getId());
        data.put("supplier_id", supplierData.getSupplier_id());
        data.put("supplier_name", supplierData.getSupplier_name());
        data.put("contact_person", supplierData.getContact_person());
        data.put("phone_number", supplierData.getPhone_number());
        data.put("email_address", supplierData.getEmail_address());
        data.put("address", supplierData.getAddress());
        data.put("city", supplierData.getCity());
        data.put("state_province", supplierData.getState_province());
        data.put("zip_postal_code", supplierData.getZip_postal_code());
        data.put("country", supplierData.getCountry());
        data.put("website", supplierData.getWebsite());
        data.put("supplier_type", supplierData.getSupplier_type());
        data.put("notes", supplierData.getNotes());
        data.put("created_by", supplierData.getCreated_by());
        data.put("tenant", supplierData.getTenant());
        data.put("created_at", String.valueOf(supplierData.getCreated_at()));
        return data;
    }

}