package com.nebula.erp.inventory.controller;

import com.nebula.erp.inventory.document.InventorySwagger;
import com.nebula.erp.inventory.model.Batch;
import com.nebula.erp.inventory.service.InventoryService;
import com.nebula.erp.inventory.utility.ApiResponseStructure;
import com.nebula.erp.inventory.utility.CreateLogger;
import com.nebula.erp.inventory.utility.JwtRequestUtils;
import com.nebula.erp.inventory.utility.PermissionHelper;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/inventories")
@Tag(name = "Inventories APIs", description = "APIs for managing Inventories")
@InventorySwagger.GlobalErrorResponse
public class InventoryController {

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${product.api}")
    private String productAPI;

    @Autowired
    private PermissionHelper permissionHelper;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/inventories";

    // Endpoint for getting inventory
    @InventorySwagger.GetAllInventoriesOperation
    @GetMapping
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getAllInventories(
            @RequestParam(value = "page", defaultValue = "0") int page,
            @RequestParam(value = "size", defaultValue = "10") int size,
            @RequestParam(value = "product_id", required = false) Long productId,
            @RequestParam(value = "brand_id", required = false) Long brandId,
            @RequestParam(value = "category_id", required = false) Long categoryId,
            @RequestParam(value = "search", required = false) String search) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-inventory")) {
                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));
            }

            Map<String, Object> serviceResult = inventoryService.getAllInventories(page, size, productId, brandId,
                    categoryId, search);

            List<Map<String, Object>> aggregatedInventory = (List<Map<String, Object>>) serviceResult.get("items");

           long totalRecords = Long.parseLong(serviceResult.get("total").toString());
            // int maxPage = (int) Math.ceil((double) totalRecords / size) - 1;
            // if (page > maxPage && maxPage >= 0) {
            //     page = 0;
            // }

            // Pagination structure
            Map<String, Object> pagination = new LinkedHashMap<>();
            pagination.put("current_page", page);
            pagination.put("per_page", size);
            pagination.put("total", totalRecords);
            pagination.put("last_page", (int) Math.ceil((double) totalRecords / size));
            pagination.put("next_page_url", null);
            pagination.put("prev_page_url", null);

            // Columns structure
            Map<String, String> columns = new LinkedHashMap<>();
            columns.put("product_id", "PRODUCT ID");
            columns.put("product_name", "PRODUCT NAME");
            columns.put("brand_id", "BRAND ID");
            columns.put("brand_name", "BRAND NAME");
            columns.put("category_id", "CATEGORY ID");
            columns.put("category_name", "CATEGORY NAME");
            columns.put("hsn_code", "HSN CODE");
            columns.put("total_quantity", "TOTAL QUANTITY");

            // Build the response data
            Map<String, Object> data = new LinkedHashMap<>();
            data.put("pagination", pagination);
            data.put("items", aggregatedInventory);
            data.put("columns", columns);

            // Create the API response
            ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success",
                    HttpStatus.OK.value(), "Inventories listed successfully", data);
            createLogger.createLogger("application", path, "GET", "Inventories listed 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));
        }
    }

    // Endpoint for getting inventory
    @InventorySwagger.GetBatchByIdOperation
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getBatchById(@PathVariable Long id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-inventory")) {
                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));
            }

            // Extract Authorization headers from the request
            HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();

            // Create an HttpEntity with the extracted headers
            HttpEntity<String> entity = new HttpEntity<>(headers);

            List<Batch> batches = inventoryService.getBatchById(id);
            Map<String, Object> productData = new LinkedHashMap<>();

            try {
                Map<String, Object> patientAPIResponse = restTemplate
                        .exchange(productAPI + '/' + id, HttpMethod.GET, entity, Map.class).getBody();
                Map<String, Object> product = (Map<String, Object>) patientAPIResponse.get("data");

                if (product != null) {
                    // Add brand and category details if available
                    productData.put("product_name", product.get("name"));
                    productData.put("brand_id", product.get("brand_id"));
                    productData.put("brand_name", product.get("brand_name"));
                    productData.put("category_id", product.get("category_id"));
                    productData.put("category_name", product.get("category_name"));
                    productData.put("unit_price", product.get("selling_price"));
                    productData.put("tax_id", product.get("tax_id"));
                    productData.put("tax_rate", product.get("tax_rate"));
                    productData.put("hsn_code", product.get("hsn_code"));
                }
            } catch (HttpClientErrorException | HttpServerErrorException ex) {
                createLogger.createLogger("error", path, "GET", ex.getMessage(), "runtime");
                if (ex.getStatusCode().value() == 404) {
                    throw new IllegalArgumentException("Medication not found for ID: " + id);
                } else {
                    throw ex;
                }
            }

            List<Map<String, Object>> batchItems = batches.stream()
                    .map(batch -> prepareBatchResponse(batch, productData))
                    .filter(Objects::nonNull) // Exclude prescriptions with no items
                    .collect(Collectors.toList());

            // Columns structure
            Map<String, String> columns = new LinkedHashMap<>();
            columns.put("product_id", "PRODUCT ID");
            columns.put("product_name", "PRODUCT NAME");
            columns.put("brand_id", "BRAND ID");
            columns.put("brand_name", "BRAND NAME");
            columns.put("category_id", "CATEGORY ID");
            columns.put("category_name", "CATEGORY NAME");
            columns.put("hsn_code", "HSN CODE");
            columns.put("total_quantity", "TOTAL QUANTITY");
            columns.put("batch_code", "BATCH CODE");
            columns.put("expiry_date", "EXPIRY DATE");
            columns.put("grn_item_id", "GRN ITEM ID");
            columns.put("manufacture_date", "MANUFACTURE DATE");

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

            // Create the API response
            ApiResponseStructure<Map<String, Object>> response = new ApiResponseStructure<>("success",
                    HttpStatus.OK.value(), "Batches listed successfully", data);
            createLogger.createLogger("application", path, "GET", "Batches listed 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));
        }
    }

    // Helper method to prepare response data for a batch
    private Map<String, Object> prepareBatchResponse(Batch batchData, Map<String, Object> productData) {
        if (batchData == null || productData == null) {
            return null;
        }
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("id", batchData.getId());
        data.put("product_id", batchData.getProduct_id());
        data.put("total_quantity", batchData.getQuantity());
        data.put("batch_code", batchData.getBatch_code());
        data.put("expiry_date", String.valueOf(batchData.getExpiry_date()));
        data.put("manufacture_date", String.valueOf(batchData.getManufacture_date()));
        data.put("grn_item_id", batchData.getGrn_item_id());

        // Add brand and category details if available
        data.put("product_name", productData.get("product_name"));
        data.put("brand_id", productData.get("brand_id"));
        data.put("brand_name", productData.get("brand_name"));
        data.put("category_id", productData.get("category_id"));
        data.put("category_name", productData.get("category_name"));
        data.put("hsn_code", productData.get("hsn_code"));
        data.put("unit_price", productData.get("unit_price"));
        data.put("tax_id", productData.get("tax_id"));
        data.put("tax_rate", productData.get("tax_rate"));
        return data;
    }

}