package com.nebula.erp.product.controller;

import com.nebula.erp.product.document.FeesSwagger;
import com.nebula.erp.product.model.Fees;
import com.nebula.erp.product.requestmodel.FeesRequest;
import com.nebula.erp.product.service.FeesService;
import com.nebula.erp.product.utility.ApiResponse;
import com.nebula.erp.product.utility.CreateLogger;
import com.nebula.erp.product.utility.JwtRequestUtils;
import com.nebula.erp.product.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.data.domain.Page;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/fees")
@Tag(name = "Fees APIs", description = "Endpoints for managing Fees")
@FeesSwagger.GlobalErrorResponse
public class FeesController {
    @Autowired
    private FeesService feesService;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${users.api}")
    private String userApiUrl;

    @Value("${practitioner.api}")
    private String practitionerApiUrl;

    @Value("${location.api}")
    private String locationApiUrl;

    @Autowired
    private PermissionHelper permissionHelper;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/fees";

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    public String fetchUserDetails(String userId) {
        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();

        // Create HttpEntity with headers
        HttpEntity<String> requestEntity = new HttpEntity<>(headers);

        try {
            String create_by = "";
            ResponseEntity<Map> response = restTemplate.exchange(userApiUrl + userId, HttpMethod.GET, requestEntity, Map.class);
            Map<String, Object> userDetails = response.getBody();

            // Extract user information from the response structure
            if (userDetails != null && "Success".equals(userDetails.get("status"))) {
                Map<String, Object> userItem = (Map<String, Object>) userDetails.get("data");
                create_by = userItem.get("firstName") + " " + userItem.get("lastName");
            } else {
                throw new IllegalArgumentException("Error getting user details!!");
            }
            return create_by;
        } catch (Exception e) {
            return "";
        }
    }

    public String fetchPractitionerDetails(String practitionerId) {
        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();

        // Create HttpEntity with headers
        HttpEntity<String> requestEntity = new HttpEntity<>(headers);

        try {
            String practitioner_name = "";
            ResponseEntity<Map> response = restTemplate.exchange(practitionerApiUrl + practitionerId, HttpMethod.GET, requestEntity, Map.class);
            Map<String, Object> userDetails = response.getBody();

            // Extract user information from the response structure
            if (userDetails != null && "Success".equals(userDetails.get("status"))) {
                Map<String, Object> userItem = (Map<String, Object>) userDetails.get("data");
                practitioner_name = userItem.get("title") + " " + userItem.get("first_name") + " " + userItem.get("last_name");
            } else {
                practitioner_name = " ";
            }
            return practitioner_name;
        } catch (Exception e) {
            return "";
        }
    }

    public String fetchLocationDetails(String locationId) {
        HttpHeaders headers = jwtRequestUtils.getAuthorizationHeaders();

        // Create HttpEntity with headers
        HttpEntity<String> requestEntity = new HttpEntity<>(headers);

        try {
            String location_name = "";
            ResponseEntity<Map> response = restTemplate.exchange(locationApiUrl + locationId, HttpMethod.GET, requestEntity, Map.class);
            Map<String, Object> locationDetails = response.getBody();

            // Extract user information from the response structure
            if (locationDetails != null && "Success".equals(locationDetails.get("status"))) {
                Map<String, Object> locationItem = (Map<String, Object>) locationDetails.get("data");
                location_name = (String)locationItem.get("name");
            } else {
                location_name = "";
            }
            return location_name;
        } catch (Exception e) {
            return "";
        }
    }

    @FeesSwagger.GetAllFeesOperation
    @GetMapping
    public ResponseEntity<ApiResponse<Map<String, Object>>> getAllFees(
            @RequestParam(value = "page", defaultValue = "1") int page,
            @RequestParam(value = "size", defaultValue = "10") int size,
            @RequestParam(value = "practitioner", required = false) String practitioner_id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-product")) {
                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 ApiResponse<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            Page<Fees> feesPage = feesService.getAllFees(page, size, practitioner_id);

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

            Map<String, String> columns = new LinkedHashMap<>();
            columns.put("id", "ID");
            columns.put("practitioner_id", "PRACTITIONER ID");
            columns.put("practitioner_name", "PRACTITIONER NAME");
            columns.put("speciality", "SPECIALITY");
            columns.put("location_id", "LOCATION ID");
            columns.put("location_name", "LOCATION NAME");
            columns.put("fees_type_id", "FEES TYPE ID");
            columns.put("fees_type_name", "FEES TYPE NAME");
            columns.put("service_category", "SERVICE CATEGORY");
            columns.put("measurement", "MEASUREMENT");
            columns.put("tax_id", "TAX ID");
            columns.put("tax_type", "TAX TYPE");
            columns.put("tax_rate", "TAX RATE");
            columns.put("rate", "RATE");
            columns.put("description", "DESCRIPTION");
            columns.put("created_by", "CREATED BY");
            columns.put("created_at", "CREATED AT");
            columns.put("updated_at", "UPDATED AT");

            List<Map<String, Object>> feesResponses = feesPage.getContent().stream()
                    .map(this::prepareFeesResponse)
                    .collect(Collectors.toList());

            Map<String, Object> data = new LinkedHashMap<>();
            data.put("pagination", pagination);
            data.put("items", feesResponses);
            data.put("columns", columns);

            ApiResponse<Map<String, Object>> response = new ApiResponse<>(
                    "success",
                    HttpStatus.OK.value(),
                    "Fees retrieved successfully",
                    data
            );
            createLogger.createLogger("application", path, "GET", "Fees 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 ApiResponse<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @FeesSwagger.CreateFeesOperation
    @PostMapping
    public ResponseEntity<ApiResponse<Fees>> createFees(@ModelAttribute FeesRequest feesRequest) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("create-product")) {
                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 ApiResponse<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            Fees newFees = feesService.createFees(feesRequest);
            ApiResponse<Fees> apiResponse = new ApiResponse<>(
                    "success",
                    HttpStatus.CREATED.value(),
                    "Fees created successfully",
                    newFees
            );
            createLogger.createLogger("application", path, "POST", "Fees created successfully", "");
            return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "POST", e.getMessage(), "runtime");
            // Generic exception handling in the controller
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponse<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @FeesSwagger.GetFeesByIdOperation
    @GetMapping("/{id}")
    public ResponseEntity<ApiResponse<Map<String, Object>>> getFeesById(@PathVariable Long id) {
        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("view-product")) {
                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 ApiResponse<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            // Fetch fees data and convert to DTO
            Optional<Fees> fessResponse = feesService.getFees(id);
            if (fessResponse.isPresent()) {
                Fees feesData = fessResponse.get();

                // Create a map to hold data
                Map<String, Object> data = new LinkedHashMap<>();
                data.put("id", feesData.getId());
                data.put("practitioner_id", feesData.getPractitioner_id());
                String practitionerName = fetchPractitionerDetails(feesData.getPractitioner_id());
                data.put("practitioner_name", practitionerName);
                data.put("speciality", feesData.getSpeciality());
                data.put("location_id", feesData.getLocation_id());
                String locationName = fetchLocationDetails(feesData.getLocation_id());
                data.put("location_name", locationName);
                data.put("fees_type_id", feesData.getFees_type_id());
                data.put("fees_type_name", feesData.getFees_type_name());
                data.put("service_category", feesData.getService_category());
                data.put("measurement", feesData.getMeasurement());
                // Tax
                if (feesData.getTax() != null) {
                    data.put("tax_id", feesData.getTax().getId());
                    data.put("tax_type", feesData.getTax().getType());
                    data.put("tax_rate", feesData.getTax().getRate());
                }
                data.put("rate", feesData.getRate());
                data.put("description", feesData.getDescription());
                data.put("created_by", feesData.getCreated_by());

                // Fetch user details
                String userDetails = fetchUserDetails(feesData.getCreated_by());

                if (userDetails != null) {
                    data.put("created_by", userDetails);
                } else {
                    data.put("created_by", feesData.getCreated_by());
                }

                data.put("created_at", feesData.getCreated_at());
                data.put("updated_at", feesData.getUpdated_at());

                // Create response structure
                ApiResponse<Map<String, Object>> response = new ApiResponse<>(
                        "success",
                        HttpStatus.OK.value(),
                        "Fees retrieved successfully",
                        data
                );
                createLogger.createLogger("application", path, "GET", "Fees retrieved successfully", "");
                return ResponseEntity.ok(response);
            } else {
                createLogger.createLogger("error", path, "GET", "Fees not found", "runtime");
                return ResponseEntity.status(HttpStatus.NOT_FOUND)
                        .body(new ApiResponse<>("error", HttpStatus.NOT_FOUND.value(), "Fees not found", null));
            }
        } catch (Exception e) {
            createLogger.createLogger("error", path, "GET", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponse<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    @FeesSwagger.UpdateFeesOperation
    @PutMapping("/{id}")
    public ResponseEntity<ApiResponse<Fees>> updateFees(
            @PathVariable Long id,
            @ModelAttribute FeesRequest feesRequest) {

        try {
            // Check user permissions
            if (!permissionHelper.hasPermission("update-product")) {
                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 ApiResponse<>("error", HttpStatus.FORBIDDEN.value(), "Forbidden: You do not have the required permission. Please contact the administration.", null));
            }

            Fees updatedFees = feesService.updateFees(id, feesRequest);

            ApiResponse<Fees> apiResponse = new ApiResponse<>(
                    "success",
                    HttpStatus.OK.value(),
                    "Fees updated successfully",
                    updatedFees
            );
            createLogger.createLogger("application", path, "PUT", "Fees updated successfully", "");
            return ResponseEntity.ok(apiResponse);
        } catch (Exception e) {
            createLogger.createLogger("error", path, "PUT", e.getMessage(), "runtime");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                    .body(new ApiResponse<>("error", HttpStatus.BAD_REQUEST.value(), e.getMessage(), null));
        }
    }

    private Map<String, Object> prepareFeesResponse(Fees feesData) {
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("id", feesData.getId());
        data.put("practitioner_id", feesData.getPractitioner_id());
        String practitionerName = fetchPractitionerDetails(feesData.getPractitioner_id());
        data.put("practitioner_name", practitionerName);
        data.put("speciality", feesData.getSpeciality());
        data.put("location_id", feesData.getLocation_id());
        String locationName = fetchLocationDetails(feesData.getLocation_id());
        data.put("location_name", locationName);
        data.put("fees_type_id", feesData.getFees_type_id());
        data.put("fees_type_name", feesData.getFees_type_name());
        data.put("service_category", feesData.getService_category());
        data.put("measurement", feesData.getMeasurement());
        // Tax
        if (feesData.getTax() != null) {
            data.put("tax_id", feesData.getTax().getId());
            data.put("tax_type", feesData.getTax().getType());
            data.put("tax_rate", feesData.getTax().getRate());
        }
        data.put("rate", feesData.getRate());
        data.put("description", feesData.getDescription());
        data.put("created_by", feesData.getCreated_by());
        data.put("created_at", feesData.getCreated_at());
        data.put("updated_at", feesData.getUpdated_at());

        return data;
    }
}