package com.nebula.erp.sales.service;

import com.nebula.erp.sales.model.PrescriptionItem;
import com.nebula.erp.sales.model.Prescriptions;
import com.nebula.erp.sales.repository.PrescriptionsRepository;
import com.nebula.erp.sales.requestmodel.PrescriptionItemRequest;
import com.nebula.erp.sales.requestmodel.PrescriptionsRequest;
import com.nebula.erp.sales.utility.JwtRequestUtils;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;

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

@Service
@Setter
@Getter
public class PrescriptionService {

    @Autowired
    private PrescriptionsRepository prescriptionRepository;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

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

    // Get all Prescriptions with pagination
    public Page<Prescriptions> getAllPrescriptions(int page, int size, String patient_id, String encounter_id) {
        String tenantName = jwtRequestUtils.getTenantName();

        Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "date"));

        // Use a specification or dynamic query to apply filters
        Specification<Prescriptions> spec = Specification.where(null);

        // Filter by tenant name
        spec = spec.and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("tenant"), tenantName));

        // Filter by patient ID if provided
        if (patient_id != null) {
            spec = spec
                    .and((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("patient_id"), patient_id));
        }

        // Filter by encounter ID if provided
        if (encounter_id != null) {
            spec = spec.and(
                    (root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("encounter_id"), encounter_id));
        }

        // Pageable pageable = PageRequest.of(page, size);
        return prescriptionRepository.findAll(spec, pageable);
    }

    // Create or update a Prescription with Prescription Items
    public Prescriptions createPrescription(PrescriptionsRequest prescriptionsRequest) {

        // Check if there is at least one Prescription item
        List<PrescriptionItemRequest> prescriptionItems = prescriptionsRequest.getPrescription_items();
        // if (prescriptionItems == null || prescriptionItems.isEmpty()) {
        // throw new IllegalArgumentException("At least one Prescription item is
        // required");
        // }

        String tenantName = jwtRequestUtils.getTenantName();
        String userId = jwtRequestUtils.getUserId();

        // Check if an existing Prescription exists for the same patient and encounter
        Optional<Prescriptions> existingPrescriptionOpt = prescriptionRepository
                .findByPatientIdAndEncounterId(prescriptionsRequest.getPatient_id(),
                        prescriptionsRequest.getEncounter_id());

        Prescriptions prescription;

        if (existingPrescriptionOpt.isPresent()) {
            // If the prescription exists, retrieve it
            prescription = existingPrescriptionOpt.get();
            // Clear the existing prescription items without replacing the entire collection
            // prescription.getPrescription_items().clear();
            // Change an Item to Append

            // Map the new Prescription Items and add them to the existing prescription
            for (PrescriptionItemRequest itemRequest : prescriptionItems) {

                PrescriptionItem item = new PrescriptionItem();
                item.setType(itemRequest.getType());
                item.setProduct_id(itemRequest.getProduct_id());
                item.setQuantity(itemRequest.getQuantity());
                item.setCreated_by(userId);
                item.setTenant(tenantName);
                item.setPrescription(prescription);

                // BED LOGIC USING ROOMS API
                if ("bed".equalsIgnoreCase(itemRequest.getType())) {

                    try {
                        String roomUrl = roomAPI + "?limit=1000&room_category=admission";

                        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();
                        HttpEntity<String> entity = new HttpEntity<>(headers);

                        RestTemplate rest = new RestTemplate();
                        ResponseEntity<Map> roomResponse = rest.exchange(roomUrl, HttpMethod.GET, entity, Map.class);

                        Map<String, Object> resp = (Map<String, Object>) roomResponse.getBody();
                        Map<String, Object> data = (Map<String, Object>) resp.get("data");
                        List<Map<String, Object>> items = (List<Map<String, Object>>) data.get("items");

                        Map<String, Object> room = items.stream()
                                .filter(r -> r.get("location_id").toString().equals(itemRequest.getProduct_id().trim()))
                                .findFirst()
                                .orElseThrow(() -> new IllegalArgumentException("Room not found for given product_id"));

                        String roomName = room.get("room_name").toString();
                        double bedRate = Double.parseDouble(room.get("bed_rate").toString());
                        long roomId = Long.parseLong(room.get("id").toString());
                        String locationId = room.get("location_id").toString();
                        String roomNumber = room.get("room_number") != null ? room.get("room_number").toString() : "-";

                        int days = itemRequest.getQuantity();

                        Object taxIdObj = room.get("tax_id");
                        Object taxRateObj = room.get("tax_rate");
                        Long taxId = taxIdObj != null ? Long.parseLong(taxIdObj.toString()) : null;
                        Double taxRate = taxRateObj != null ? Double.parseDouble(taxRateObj.toString()) : 0.0;

                        item.setRoom_id(roomId);
                        item.setLocation_id(locationId);
                        item.setRoom_number(roomNumber);
                        item.setTax_id(taxId);
                        item.setTax_rate(taxRate);

                        item.setProduct_name(roomName);
                        item.setProduct_price(bedRate);
                        item.setTotal_price(bedRate * days);

                    } catch (Exception e) {
                        throw new IllegalArgumentException("Room not found. Cannot create bed prescription.");
                    }

                } else {
                    // REGULAR PRODUCT / SERVICE / PACKAGE
                    item.setProduct_name(itemRequest.getProduct_name());
                    item.setProduct_price(itemRequest.getProduct_price());
                    item.setTotal_price(itemRequest.getProduct_price() * itemRequest.getQuantity());
                }

                prescription.getPrescription_items().add(item);
            }
        } else {
            // If no existing prescription, create a new one
            prescription = new Prescriptions();
            prescription.setPatient_id(prescriptionsRequest.getPatient_id());
            prescription.setDoctor_id(prescriptionsRequest.getDoctor_id());
            prescription.setEncounter_id(prescriptionsRequest.getEncounter_id());
            prescription.setCustom_encounter_id(prescriptionsRequest.getCustom_encounter_id());
            prescription.setDate(prescriptionsRequest.getDate());
            prescription.setCreated_by(userId);
            prescription.setTenant(tenantName);

            // Create Prescription Items
            List<PrescriptionItem> prescriptionItemList = prescriptionItems.stream().map(itemRequest -> {
                PrescriptionItem prescriptionItem = new PrescriptionItem();
                prescriptionItem.setType(itemRequest.getType());
                prescriptionItem.setProduct_id(itemRequest.getProduct_id());
                prescriptionItem.setProduct_name(itemRequest.getProduct_name());
                prescriptionItem.setProduct_price(itemRequest.getProduct_price());
                prescriptionItem.setQuantity(itemRequest.getQuantity());
                if ("bed".equalsIgnoreCase(itemRequest.getType())) {
                    try {
                        String roomUrl = roomAPI + "?limit=1000&room_category=admission";

                        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();
                        HttpEntity<String> entity = new HttpEntity<>(headers);

                        RestTemplate rest = new RestTemplate();
                        ResponseEntity<Map> roomResponse = rest.exchange(roomUrl, HttpMethod.GET, entity, Map.class);
                        Map<String, Object> resp = roomResponse.getBody();

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

                        if (items == null || items.isEmpty()) {
                            throw new IllegalArgumentException("Invalid room selection");
                        }

                        Map<String, Object> room = items.stream()
                                .filter(r -> r.get("location_id").toString().equals(itemRequest.getProduct_id().trim()))
                                .findFirst()
                                .orElseThrow(() -> new IllegalArgumentException("Room not found for given product_id"));

                        String roomName = room.get("room_name").toString();
                        double bedRate = Double.parseDouble(room.get("bed_rate").toString());
                        long roomId = Long.parseLong(room.get("id").toString());
                        String locationId = room.get("location_id").toString();
                        String roomNumber = room.get("room_number") != null ? room.get("room_number").toString() : "-";

                        int days = itemRequest.getQuantity();
                        Object taxIdObj = room.get("tax_id");
                        Object taxRateObj = room.get("tax_rate");
                        Long taxId = taxIdObj != null ? Long.parseLong(taxIdObj.toString()) : null;
                        Double taxRate = taxRateObj != null ? Double.parseDouble(taxRateObj.toString()) : 0.0;

                        prescriptionItem.setRoom_id(roomId);
                        prescriptionItem.setLocation_id(locationId);
                        prescriptionItem.setRoom_number(roomNumber);
                        prescriptionItem.setTax_id(taxId);
                        prescriptionItem.setTax_rate(taxRate);

                        prescriptionItem.setProduct_name(roomName);
                        prescriptionItem.setProduct_price(bedRate);
                        prescriptionItem.setTotal_price(bedRate * days);

                    } catch (Exception e) {
                        throw new IllegalArgumentException("Room not found. Cannot create bed prescription.");
                    }

                } else {
                    prescriptionItem.setProduct_name(itemRequest.getProduct_name());
                    prescriptionItem.setProduct_price(itemRequest.getProduct_price());
                    prescriptionItem.setTotal_price(itemRequest.getProduct_price() * itemRequest.getQuantity());
                }

                prescriptionItem.setCreated_by(userId);
                prescriptionItem.setTenant(tenantName);
                prescriptionItem.setPrescription(prescription); // Link PrescriptionItem with Prescription
                return prescriptionItem;
            }).collect(Collectors.toList());

            // Link PrescriptionItems to Prescription
            prescription.setPrescription_items(prescriptionItemList);
        }

        // Save the updated Prescription (and associated new PrescriptionItems)
        return prescriptionRepository.save(prescription);
    }

    // Retrieve Prescription by ID
    public Optional<Prescriptions> getPrescription(Long id) {
        String tenantName = jwtRequestUtils.getTenantName();
        return prescriptionRepository.findByIdAndTenant(id, tenantName);
    }

    public void deletePrescriptionItem(Long itemId) {
        String tenantName = jwtRequestUtils.getTenantName();

        // Find the prescription that contains this item
        Prescriptions prescription = prescriptionRepository.findAll().stream()
                .filter(p -> p.getTenant().equals(tenantName))
                .filter(p -> p.getPrescription_items().stream()
                        .anyMatch(item -> item.getId().equals(itemId)))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Prescription item not found"));

        // Find the specific item
        PrescriptionItem itemToDelete = prescription.getPrescription_items().stream()
                .filter(item -> item.getId().equals(itemId))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Prescription item not found"));

        // Only allow deletion of product type items
        if (!"product".equalsIgnoreCase(itemToDelete.getType())) {
            throw new IllegalArgumentException(
                    "Only product type items can be deleted. Item type '" + itemToDelete.getType()
                            + "' cannot be deleted.");
        }

        prescription.getPrescription_items().remove(itemToDelete);
        prescriptionRepository.save(prescription);
    }

}