package com.nebula.erp.sales.controller;

import com.nebula.erp.sales.model.Prescriptions;
import com.nebula.erp.sales.requestmodel.PrescriptionsRequest;
import com.nebula.erp.sales.service.PrescriptionService;
import com.nebula.erp.sales.utility.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import com.nebula.erp.sales.document.PrescriptionSwagger;
import java.util.*;
import java.util.stream.Collectors;

// Import Swagger annotations
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/api/prescriptions")
@Tag(name = "Prescriptions APIs", description = "API for managing Prescriptions and Prescription Items")
@PrescriptionSwagger.GlobalErrorResponse
public class PrescriptionsController {

    @Autowired
    private PrescriptionService prescriptionService;

    @Autowired
    private RestTemplate restTemplate;

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

    @Value("${inventory.api}")
    private String inventoryAPI;

    @Value("${service.api}")
    private String serviceAPI;

    @Value("${package.api}")
    private String packageAPI;

    @Value("${encounter.api}")
    private String encounterAPI;

    @Value("${patient.api}")
    private String patientAPI;

    @Value("${room.api}")
    private String roomAPI;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private PermissionHelper permissionHelper;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/prescriptions";

    @PrescriptionSwagger.CreatePrescriptionOperation
    @PostMapping
    public ResponseEntity<ApiResponseStructure<Prescriptions>> createPrescription(
            @RequestBody PrescriptionsRequest prescriptionRequest) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("create-sales")) {
                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));
            }

            Prescriptions createdPrescription = prescriptionService.createPrescription(prescriptionRequest);
            ApiResponseStructure<Prescriptions> response = new ApiResponseStructure<>("success",
                    HttpStatus.CREATED.value(), "Prescription created successfully", createdPrescription);
            createLogger.createLogger("application", path, "POST", "Prescription 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));
        }
    }

    @PrescriptionSwagger.GetPrescriptionByIdOperation
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getPrescriptionById(@PathVariable Long id) {
        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));
            }

            Optional<Prescriptions> prescriptionOptional = prescriptionService.getPrescription(id);
            if (prescriptionOptional.isPresent()) {
                Prescriptions prescriptionData = prescriptionOptional.get();

                // Create a map to hold prescription data
                Map<String, Object> data = preparePrescriptionsResponse(prescriptionData);

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

    @PrescriptionSwagger.GetAllPrescriptionsOperation
    @GetMapping
    public ResponseEntity<ApiResponseStructure<Map<String, Object>>> getAllPrescriptions(
            @RequestParam(value = "page", defaultValue = "1") int page,
            @RequestParam(value = "size", defaultValue = "10") int size,
            @RequestParam(value = "patient_id", required = false) String patient_id,
            @RequestParam(value = "encounter_id", required = false) String encounter_id) {
        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));
            }

            Page<Prescriptions> prescriptionPage = prescriptionService.getAllPrescriptions(page, size, patient_id,
                    encounter_id);

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

            // Define columns for prescription and nested prescription items
            Map<String, String> columns = new LinkedHashMap<>();
            columns.put("id", "ID");
            columns.put("patient_id", "PATIENT ID");
            columns.put("doctor_id", "DOCTOR ID");
            columns.put("encounter_id", "ENCOUNTER ID");
            columns.put("date", "DATE");
            columns.put("created_by", "CREATED BY");
            columns.put("tenant", "TENANT");
            columns.put("created_at", "CREATED AT");

            List<Map<String, Object>> prescriptionItems = prescriptionPage.getContent().stream()
                    .map(this::preparePrescriptionsResponse)
                    .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", prescriptionItems);
            data.put("columns", columns);

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

    // Helper method to prepare response data for a prescription (including items)
    private Map<String, Object> preparePrescriptionsResponse(Prescriptions prescriptionsData) {
        // Extract Authorization headers from the request
        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();

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

        Map<String, Object> data = new LinkedHashMap<>();
        data.put("id", prescriptionsData.getId());
        data.put("patient_id", prescriptionsData.getPatient_id());
        data.put("doctor_id", prescriptionsData.getDoctor_id());
        data.put("encounter_id", prescriptionsData.getEncounter_id());
        data.put("custom_encounter_id", prescriptionsData.getCustom_encounter_id());

        // Get doctor name by encounter ID
        try {
            Map<String, Object> encounterData = restTemplate
                    .exchange(encounterAPI + prescriptionsData.getEncounter_id(), HttpMethod.GET, entity, Map.class)
                    .getBody();
            Map<String, Object> encounterItem = (Map<String, Object>) encounterData.get("data");

            if (encounterItem != null) {
                data.put("patient_name", encounterItem.get("patient_name"));
                data.put("practitioner_name", encounterItem.get("practitioner_name"));
            } else {
                data.put("patient_name", "-");
                data.put("practitioner_name", "-");
            }
        } catch (HttpClientErrorException | HttpServerErrorException ex) {
            if (ex.getStatusCode().value() == 500 || ex.getStatusCode().value() == 404) {
                data.put("patient_name", "-");
                data.put("practitioner_name", "-");
            } else {
                throw ex;
            }
        }

        // Get patient information by patient ID
        try {
            Map<String, Object> patientData = restTemplate
                    .exchange(patientAPI + prescriptionsData.getPatient_id(), HttpMethod.GET, entity, Map.class)
                    .getBody();
            Map<String, Object> patientItem = (Map<String, Object>) patientData.get("data");

            if (patientItem != null) {
                data.put("customer_name", patientItem.get("name"));
                data.put("customer_mobile", patientItem.get("contact_mobile_number"));
                data.put("customer_email", patientItem.get("contact_email_id"));
                data.put("customer_dob", patientItem.get("date_of_birth"));
                data.put("customer_gender", patientItem.get("gender"));

                String address = getOrEmpty(patientItem.get("contact_address"))
                        + getOrEmpty(patientItem.get("contact_city"))
                        + getOrEmpty(patientItem.get("contact_district"))
                        + getOrEmpty(patientItem.get("contact_state"))
                        + getOrEmpty(patientItem.get("contact_country"))
                        + getOrEmpty(patientItem.get("contact_postal_code"));

                data.put("customer_address", cleanAddress(address));
            } else {
                data.put("customer_name", "-");
                data.put("customer_mobile", "-");
                data.put("customer_email", "-");
                data.put("customer_dob", "-");
                data.put("customer_address", "-");
                data.put("customer_gender", "-");
            }
        } catch (HttpClientErrorException | HttpServerErrorException ex) {
            if (ex.getStatusCode().value() == 500 || ex.getStatusCode().value() == 404) {
                data.put("customer_name", "-");
                data.put("customer_mobile", "-");
                data.put("customer_email", "-");
                data.put("customer_dob", "-");
                data.put("customer_address", "-");
                data.put("customer_gender", "-");
            } else {
                throw ex;
            }
        }

        data.put("date", String.valueOf(prescriptionsData.getDate()));
        data.put("created_by", prescriptionsData.getCreated_by());
        data.put("tenant", prescriptionsData.getTenant());
        data.put("created_at", String.valueOf(prescriptionsData.getCreated_at()));

        // Map prescriptions items
        List<Map<String, Object>> prescriptionItemsData = prescriptionsData.getPrescription_items().stream()
                .filter(item -> Boolean.FALSE.equals(item.getIs_sale()))
                .map(item -> {
                    Map<String, Object> itemData = new LinkedHashMap<>();
                    itemData.put("id", item.getId());
                    itemData.put("type", item.getType());
                    itemData.put("product_id", item.getProduct_id());

                    if ((item.getProduct_id() != null) && "product".equals(item.getType())) {
                        try {
                            Map<String, Object> productData = restTemplate
                                    .exchange(productAPI + item.getProduct_id(), HttpMethod.GET, entity, Map.class)
                                    .getBody();
                            List<Map<String, Object>> items = (List<Map<String, Object>>) ((Map<String, Object>) productData
                                    .get("data")).get("items");

                            if (items != null && !items.isEmpty()) {
                                // Extract the first product's details
                                Map<String, Object> product = items.get(0);

                                // Add brand and category details if available
                                itemData.put("product_name", product.get("name"));
                                itemData.put("brand_id", product.get("brand_id"));
                                itemData.put("brand_name", product.get("brand_name"));
                                itemData.put("category_id", product.get("category_id"));
                                itemData.put("category_name", product.get("category_name"));
                                itemData.put("unit_price", product.get("selling_price"));
                                itemData.put("tax_id", product.get("tax_id"));
                                itemData.put("tax_rate", product.get("tax_rate"));
                            }
                        } catch (HttpClientErrorException | HttpServerErrorException ex) {
                            throw ex;
                        }

                        try {
                            String inventoryUrl = inventoryAPI + item.getProduct_id() + "&page=1&size=1000";

                            Map<String, Object> inventoryData = restTemplate
                                    .exchange(inventoryUrl, HttpMethod.GET, entity, Map.class)
                                    .getBody();

                            List<Map<String, Object>> inventoryItems = (List<Map<String, Object>>) ((Map<String, Object>) inventoryData
                                    .get("data")).get("items");
                            if (inventoryItems != null && !inventoryItems.isEmpty()) {
                                int totalStock = inventoryItems.stream().mapToInt(inv -> {
                                    Object qty = inv.get("total_quantity");
                                    return qty != null ? Integer.parseInt(qty.toString()) : 0;
                                })
                                        .sum();

                                itemData.put("stock_quantity", totalStock);

                            } else {
                                itemData.put("stock_quantity", 0);
                            }
                        } catch (HttpClientErrorException | HttpServerErrorException ex) {
                            throw ex;
                        }
                    } else if ((item.getProduct_id() != null) && "service".equals(item.getType())) {
                        try {
                            if (ObjectUtils.isEmpty(item.getProduct_id())) {
                                itemData.put("product_name", item.getProduct_name());
                                itemData.put("rate", MoneyUtils.truncateToTwoDecimals(item.getProduct_price()));
                            } else {
                                Map<String, Object> serviceData = restTemplate
                                        .exchange(serviceAPI + item.getProduct_id(), HttpMethod.GET, entity, Map.class)
                                        .getBody();
                                Map<String, Object> serviceItem = (Map<String, Object>) serviceData.get("data");

                                if (serviceItem != null) {
                                    itemData.put("product_name", serviceItem.get("service_name"));
                                    itemData.put("tax_id", serviceItem.get("tax_id"));
                                    itemData.put("tax_rate", serviceItem.get("tax_rate"));
                                    itemData.put("rate", serviceItem.get("rate"));
                                }
                            }
                        } catch (HttpClientErrorException | HttpServerErrorException ex) {
                            throw ex;
                        }
                    } else if ("package".equals(item.getType())) {
                        try {
                            Map<String, Object> packageResp = restTemplate
                                    .exchange(packageAPI + item.getProduct_id(), HttpMethod.GET, entity, Map.class)
                                    .getBody();

                            List<Map<String, Object>> itemsList = (List<Map<String, Object>>) ((Map<String, Object>) packageResp
                                    .get("data")).get("items");

                            if (itemsList != null && !itemsList.isEmpty()) {
                                Map<String, Object> pkg = itemsList.get(0);

                                itemData.put("product_name", pkg.get("package_name"));
                                itemData.put("tax_id", pkg.get("tax_id"));
                                itemData.put("tax_rate", pkg.get("tax_rate"));
                                itemData.put("rate", pkg.get("rate"));
                            } else {
                                itemData.put("product_name", item.getProduct_name());
                                itemData.put("rate", item.getProduct_price());
                            }

                        } catch (Exception ex) {
                            itemData.put("product_name", item.getProduct_name());
                            itemData.put("rate", item.getProduct_price());
                        }
                    } else if ("bed".equals(item.getType())) {

                        // Add room_id & location_id stored in DB
                        itemData.put("room_id", item.getRoom_id());
                        itemData.put("location_id", item.getLocation_id());
                        itemData.put("room_number", item.getRoom_number());

                        if (item.getProduct_id() == null || item.getProduct_id().trim().isEmpty()) {
                            itemData.put("product_name", "Room Not Available");
                            itemData.put("unit_price", 0);
                            itemData.put("tax_id", null);
                            itemData.put("tax_rate", 0);
                            itemData.put("total_price", item.getTotal_price());
                            return itemData;
                        }

                        try {
                            // Correct URL: /rooms?location_id=
                            String url = roomAPI + "?limit=1000&room_category=admission";

                            Map<String, Object> roomResp = restTemplate
                                    .exchange(url, HttpMethod.GET, entity, Map.class)
                                    .getBody();

                            if (roomResp == null || !(roomResp.get("data") instanceof Map)) {
                                itemData.put("product_name", "Room Not Found");
                                itemData.put("unit_price", 0.0);
                                itemData.put("total_price", item.getTotal_price());
                                return itemData;
                            }

                            Map<String, Object> dataObj = (Map<String, Object>) roomResp.get("data");
                            List<Map<String, Object>> itemsList = (List<Map<String, Object>>) dataObj.get("items");

                            if (itemsList == null || itemsList.isEmpty()) {
                                itemData.put("product_name", "Room Not Found");
                                itemData.put("unit_price", 0.0);
                                itemData.put("total_price", item.getTotal_price());
                                return itemData;
                            }

                            // Find the matching room by product_id (location_id)
                            Map<String, Object> matchedRoom = itemsList.stream()
                                    .filter(r -> item.getProduct_id().equals(r.get("location_id")))
                                    .findFirst()
                                    .orElse(itemsList.get(0));

                            // Extract tax_id and tax_rate from matched room
                            Object taxId = matchedRoom.get("tax_id");
                            Object taxRate = matchedRoom.get("tax_rate");

                            // Final Response Output
                            itemData.put("product_name", item.getProduct_name());
                            itemData.put("unit_price", item.getProduct_price());
                            itemData.put("tax_id", taxId);
                            itemData.put("tax_rate", taxRate != null ? Double.parseDouble(taxRate.toString()) : 0);
                            itemData.put("total_price", item.getTotal_price());
                        } catch (Exception ex) {
                            itemData.put("product_name", "Room Not Found");
                            itemData.put("unit_price", 0.0);
                            itemData.put("tax_id", null);
                            itemData.put("tax_rate", 0.0);
                            itemData.put("total_price", item.getTotal_price());
                        }

                    } else {
                        itemData.put("product_name", item.getProduct_name());
                        itemData.put("unit_price", item.getProduct_price());
                    }

                    itemData.put("quantity", item.getQuantity());
                    itemData.put("created_by", item.getCreated_by());
                    itemData.put("tenant", item.getTenant());
                    itemData.put("created_at", String.valueOf(item.getCreated_at()));
                    return itemData;
                }).collect(Collectors.toList());
        if (prescriptionItemsData.isEmpty())

        {
            return null;
        }
        data.put("prescriptions_items", prescriptionItemsData);

        return data;
    }

    // Main method with custom default
    private String getOrEmpty(Object value) {
        return value == null ? "" : ", " + value.toString();
    }

    private String cleanAddress(String address) {
        if (address != null && address.startsWith(",")) {
            return address.substring(1).trim();
        }
        return address != null ? address.trim() : "";
    }

    @DeleteMapping("/item/{itemId}")
    public ResponseEntity<ApiResponseStructure<String>> deletePrescriptionItem(@PathVariable Long itemId) {
        try {
            if (!permissionHelper.hasPermission("create-sales")) {
                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));
            }

            prescriptionService.deletePrescriptionItem(itemId);
            createLogger.createLogger("application", path, "DELETE", "Prescription item deleted successfully", "");
            return ResponseEntity.ok(new ApiResponseStructure<>("success", HttpStatus.OK.value(),
                    "Prescription item deleted successfully", null));

        } catch (IllegalArgumentException e) {
            createLogger.createLogger("error", path, "DELETE", e.getMessage(), "validation");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponseStructure<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        } catch (Exception e) {
            createLogger.createLogger("error", path, "DELETE", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ApiResponseStructure<>("error", HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(),
                            null));
        }
    }

}