package com.healthcare.ohctech.controller;

import com.healthcare.ohctech.dto.CheckupParameterDto;
import com.healthcare.ohctech.entity.*;
import com.healthcare.ohctech.repository.*;
import com.healthcare.ohctech.service.impl.AuthServiceImpl;
import com.healthcare.ohctech.service.impl.CheckupParameterServiceImpl;
import com.healthcare.ohctech.util.PaginationUtil;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/checkup-parameters")
public class CheckupParameterController {

    @Autowired
    private CheckupParameterServiceImpl checkupParameterServiceImpl;
    @Autowired
    private AuthServiceImpl authServiceImpl;
    @Autowired
    private CheckupFormSectionRepo checkupFormSectionRepo;
    @Autowired
    private KeyHealthReportableParameterRepo keyHealthReportableParameterRepo;
    @Autowired
    private CheckupParameterUnitMasterRepo checkupParameterUnitMasterRepo;
    @Autowired
    private DeviceMasterRepo deviceMasterRepo;
    @Autowired
    private HealthRiskRepo healthRiskRepo;
    @Autowired
    private HealthAdviceRepo healthAdviceRepo;
    @Autowired
    private CheckupParameterValueRepo checkupParameterValueRepo;
    @Autowired
    private CheckupTypeRepo checkupTypeRepo;
    @Autowired
    private RuleEquationRepo ruleEquationRepo;

    @GetMapping("/{parameterId}")
    public ResponseEntity<?> getCheckupParameterById(@PathVariable Long parameterId) {
        CheckupParameter checkupParameter = checkupParameterServiceImpl.getCheckupParameterById(parameterId);

        List<Map<String, Object>> lessAdvicesDetails = Arrays.stream(checkupParameter.getLessAdvicesIds().split(","))
                .map(Long::valueOf)
                .map(id -> healthAdviceRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(advice -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", advice.getId());
                    map.put("label", advice.getHealthAdviceName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> moreAdvicesDetails = Arrays.stream(checkupParameter.getMoreAdvicesIds().split(","))
                .map(Long::valueOf)
                .map(id -> healthAdviceRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(advice -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", advice.getId());
                    map.put("label", advice.getHealthAdviceName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> moreRisksDetails = Arrays.stream(checkupParameter.getMoreRisksIds().split(","))
                .map(Long::valueOf)
                .map(id -> healthRiskRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(risk -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", risk.getId());
                    map.put("label", risk.getHealthRiskName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> lessRisksDetails = Arrays.stream(checkupParameter.getLessRisksIds().split(","))
                .map(Long::valueOf)
                .map(id -> healthRiskRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(risk -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", risk.getId());
                    map.put("label", risk.getHealthRiskName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> parameterValueDetails = Arrays.stream(checkupParameter.getParameterValueIds().split(","))
                .map(Long::valueOf)
                .map(id -> checkupParameterValueRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(parameterValue -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", parameterValue.getId());
                    map.put("label", parameterValue.getParameterValueName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> checkupTypeDetails = Arrays.stream(checkupParameter.getCheckupTypeIds().split(","))
                .map(Long::valueOf)
                .map(id -> checkupTypeRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(checkupType -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", checkupType.getId());
                    map.put("label", checkupType.getCheckupTypeName());
                    return map;
                })
                .collect(Collectors.toList());

        List<Map<String, Object>> ruleDetails = Arrays.stream(checkupParameter.getRuleIds().split(","))
                .map(Long::valueOf)
                .map(id -> ruleEquationRepo.findById(id).orElse(null))
                .filter(Objects::nonNull)
                .map(rule -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", rule.getId());
                    map.put("label", rule.getRuleEquation());
                    return map;
                })
                .collect(Collectors.toList());

        Map<String, Object> sectionDetails = checkupFormSectionRepo.findById(checkupParameter.getCheckupFormSection().getId())
                .map(section -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", section.getId());
                    map.put("label", section.getSectionName());
                    return map;
                })
                .orElseGet(() -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", " ");
                    map.put("label", " ");
                    return map;
                });

        Map<String, Object> keyHealthReportableParam = keyHealthReportableParameterRepo.findById(checkupParameter.getKeyHealthReportableParameter().getId())
                .map(param -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", param.getId());
                    map.put("label", param.getKeyParamName());
                    return map;
                })
                .orElseGet(() -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", " ");
                    map.put("label", " ");
                    return map;
                });

        Map<String, Object> checkupParameterUnit = checkupParameterUnitMasterRepo.findById(checkupParameter.getCheckupParameterUnitMaster().getId())
                .map(unit -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", unit.getId());
                    map.put("label", unit.getUnitName());
                    return map;
                })
                .orElseGet(() -> {
                    Map<String, Object> map = new LinkedHashMap<>();
                    map.put("id", " ");
                    map.put("label", " ");
                    return map;
                });

//        Map<String, Object> deviceDetails = deviceMasterRepo.findById(checkupParameter.getDeviceMaster().getId())
//                .map(device -> {
//                    Map<String, Object> map = new LinkedHashMap<>();
//                    map.put("id", device.getId());
//                    map.put("label", device.getDeviceName());
//                    return map;
//                })
//                .orElseGet(() -> {
//                    Map<String, Object> map = new LinkedHashMap<>();
//                    map.put("id", " ");
//                    map.put("label", " ");
//                    return map;
//                });

        Map<String, Object> response = new LinkedHashMap<>();
        response.put("id", checkupParameter.getId());
        response.put("parameterName", checkupParameter.getParameterName());
        response.put("startingRange", checkupParameter.getStartingRange());
        response.put("endingRange", checkupParameter.getEndingRange());
        response.put("patientCategory", checkupParameter.getPatientCategory());
        response.put("lessAdvices", lessAdvicesDetails);
        response.put("moreAdvices", moreAdvicesDetails);
        response.put("moreRisks", moreRisksDetails);
        response.put("lessRisks", lessRisksDetails);
        response.put("checkupFormSection", sectionDetails);
        response.put("columnOrder", checkupParameter.getColumnOrder());
        response.put("columnName", checkupParameter.getColumnName());
        response.put("groupId", checkupParameter.getGroupId());
        response.put("placeHolderName", checkupParameter.getPlaceHolderName());
        response.put("parameterValues", parameterValueDetails);
        response.put("inputType", checkupParameter.getInputType());
        response.put("checkupTypes", checkupTypeDetails);
        response.put("enabled", checkupParameter.getEnabled());
        response.put("hearId", checkupParameter.getHearId());
        response.put("readonlyField", checkupParameter.getReadonlyField());
        response.put("keyHealthReportableParameter", keyHealthReportableParam);
        response.put("refRanges", checkupParameter.getRefRanges());
        response.put("checkupParameterUnitMaster", checkupParameterUnit);
        response.put("opdParam", checkupParameter.getOpdParam());
        response.put("rules", ruleDetails);
        response.put("ipdParam", checkupParameter.getIpdParam());
        response.put("injParam", checkupParameter.getInjParam());
        response.put("parentParam", checkupParameter.getParentParam());
//        response.put("deviceMaster", deviceDetails);
        response.put("isMandatory", checkupParameter.getIsMandatory());
        response.put("defaultValue", checkupParameter.getDefaultValue());
        response.put("modifiedBy", checkupParameter.getModifiedBy());
        response.put("lastModified", checkupParameter.getLastModified());

        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    @GetMapping
    public ResponseEntity<?> getAllCheckupParameters(@RequestParam(required = false) Integer page,
                                                     @RequestParam(required = false) Integer size,
                                                     @RequestParam(required = false) String sortBy,
                                                     @RequestParam(required = false) String sortOrder) {
        Pageable pageable = PaginationUtil.getPageableWithDefaults(page, size, sortBy, sortOrder);
        Page<CheckupParameter> checkupParameterPage = checkupParameterServiceImpl.getAllCheckupParameters(pageable);

        Page<Map<String, Object>> dtoPage = checkupParameterPage.map(checkupParameter -> {
            List<String> lessAdvicesNames = Arrays.stream(checkupParameter.getLessAdvicesIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> healthAdviceRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(HealthAdvice::getHealthAdviceName)
                    .collect(Collectors.toList());

            List<String> moreAdvicesNames = Arrays.stream(checkupParameter.getMoreAdvicesIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> healthAdviceRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(HealthAdvice::getHealthAdviceName)
                    .collect(Collectors.toList());

            List<String> moreRisksNames = Arrays.stream(checkupParameter.getMoreRisksIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> healthRiskRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(HealthRisk::getHealthRiskName)
                    .collect(Collectors.toList());

            List<String> lessRisksNames = Arrays.stream(checkupParameter.getLessRisksIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> healthRiskRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(HealthRisk::getHealthRiskName)
                    .collect(Collectors.toList());

            List<String> parameterValueNames = Arrays.stream(checkupParameter.getParameterValueIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> checkupParameterValueRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(CheckupParameterValue::getParameterValueName)
                    .collect(Collectors.toList());

            List<String> checkupTypeNames = Arrays.stream(checkupParameter.getCheckupTypeIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> checkupTypeRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(CheckupType::getCheckupTypeName)
                    .collect(Collectors.toList());

            List<String> ruleNames = Arrays.stream(checkupParameter.getRuleIds().split(","))
                    .map(Long::valueOf)
                    .map(id -> ruleEquationRepo.findById(id).orElse(null))
                    .filter(Objects::nonNull)
                    .map(RuleEquation::getRuleEquation)
                    .collect(Collectors.toList());

            String sectionName = checkupFormSectionRepo.findById(checkupParameter.getCheckupFormSection().getId())
                    .map(CheckupFormSection::getSectionName)
                    .orElse("Unknown");

            String keyHealthReportableParamName = keyHealthReportableParameterRepo.findById(checkupParameter.getKeyHealthReportableParameter().getId())
                    .map(KeyHealthReportableParameter::getKeyParamName)
                    .orElse("Unknown");

            String checkupParameterUnitName = checkupParameterUnitMasterRepo.findById(checkupParameter.getCheckupParameterUnitMaster().getId())
                    .map(CheckupParameterUnitMaster::getUnitName)
                    .orElse("Unknown");

//            String deviceName = deviceMasterRepo.findById(checkupParameter.getDeviceMaster().getId())
//                    .map(DeviceMaster::getDeviceName)
//                    .orElse("Unknown");

            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", checkupParameter.getId());
            map.put("parameterName", checkupParameter.getParameterName());
            map.put("startingRange", checkupParameter.getStartingRange());
            map.put("endingRange", checkupParameter.getEndingRange());
            map.put("patientCategory", checkupParameter.getPatientCategory());
            map.put("lessAdvices", lessAdvicesNames);
            map.put("moreAdvices", moreAdvicesNames);
            map.put("moreRisks", moreRisksNames);
            map.put("lessRisks", lessRisksNames);
            map.put("checkupFormSection", sectionName);
            map.put("columnOrder", checkupParameter.getColumnOrder());
            map.put("columnName", checkupParameter.getColumnName());
            map.put("groupId", checkupParameter.getGroupId());
            map.put("placeHolderName", checkupParameter.getPlaceHolderName());
            map.put("parameterValues", parameterValueNames);
            map.put("inputType", checkupParameter.getInputType());
            map.put("checkupTypes", checkupTypeNames);
            map.put("enabled", checkupParameter.getEnabled());
            map.put("hearId", checkupParameter.getHearId());
            map.put("readonlyField", checkupParameter.getReadonlyField());
            map.put("keyHealthReportableParameter", keyHealthReportableParamName);
            map.put("refRanges", checkupParameter.getRefRanges());
            map.put("checkupParameterUnitMaster", checkupParameterUnitName);
            map.put("opdParam", checkupParameter.getOpdParam());
            map.put("rules", ruleNames);
            map.put("ipdParam", checkupParameter.getIpdParam());
            map.put("injParam", checkupParameter.getInjParam());
            map.put("parentParam", checkupParameter.getParentParam());
//            map.put("deviceMaster", deviceName);
            map.put("isMandatory", checkupParameter.getIsMandatory());
            map.put("defaultValue", checkupParameter.getDefaultValue());
            map.put("modifiedBy", checkupParameter.getModifiedBy());
            map.put("lastModified", checkupParameter.getLastModified());

            return map;
        });

        Map<String, Object> response = PaginationUtil.getPageResponse(dtoPage);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity<?> addCheckupParameter(@Valid @RequestBody CheckupParameterDto checkupParameterDto) {
        Long userId = authServiceImpl.getCurrentUserId();
        checkupParameterServiceImpl.addCheckupParameter(checkupParameterDto, userId);
        return new ResponseEntity<>("Saved Successfully", HttpStatus.CREATED);
    }

    @PutMapping("/{parameterId}")
    public ResponseEntity<?> updateCheckupParameter(@Valid @RequestBody CheckupParameterDto checkupParameterDto) {
        Long userId = authServiceImpl.getCurrentUserId();
        checkupParameterServiceImpl.updateCheckupParameter(checkupParameterDto, userId);
        return new ResponseEntity<>("Updated Successfully", HttpStatus.OK);
    }

    @DeleteMapping("/{parameterId}")
    public ResponseEntity<?> deleteCheckupParameter(@PathVariable Long parameterId) {
        checkupParameterServiceImpl.deleteCheckupParameter(parameterId);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}