package com.saas.tenant.service;

import com.saas.tenant.dto.request.CreateDoctorRequest;
import com.saas.tenant.dto.request.UpdateDoctorRequest;
import com.saas.tenant.dto.response.DoctorResponse;
import com.saas.tenant.entity.Doctor;
import com.saas.tenant.entity.DoctorStatus;
import com.saas.tenant.repository.DoctorRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class DoctorService {

    private final DoctorRepository doctorRepository;

    @Transactional
    public DoctorResponse createDoctor(CreateDoctorRequest request) {
        log.info("Creating new doctor: {} {}", request.getFirstName(), request.getLastName());

        Doctor doctor = new Doctor();
        doctor.setFirstName(request.getFirstName());
        doctor.setLastName(request.getLastName());
        doctor.setMedicalSpecialty(request.getMedicalSpecialty());
        doctor.setGender(request.getGender());
        doctor.setDepartment(request.getDepartment());
        doctor.setLanguagesSpoken(request.getLanguagesSpoken());
        doctor.setInternalCode(request.getInternalCode());
        doctor.setContractType(request.getContractType());
        doctor.setStatus(request.getStatus());
        doctor.setBiography(request.getBiography());
        doctor.setMedicalActsPerformed(request.getMedicalActsPerformed());
        doctor.setEmail(request.getEmail());
        doctor.setPhoneNumber(request.getPhoneNumber());
        doctor.setLicenseNumber(request.getLicenseNumber());

        Doctor savedDoctor = doctorRepository.save(doctor);
        log.info("Doctor created successfully with ID: {}", savedDoctor.getId());

        return mapToResponse(savedDoctor);
    }

    @Transactional
    public DoctorResponse updateDoctor(Long id, UpdateDoctorRequest request) {
        log.info("Updating doctor with ID: {}", id);

        Doctor doctor = doctorRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Doctor not found with ID: " + id));

        if (request.getFirstName() != null)
            doctor.setFirstName(request.getFirstName());
        if (request.getLastName() != null)
            doctor.setLastName(request.getLastName());
        if (request.getMedicalSpecialty() != null)
            doctor.setMedicalSpecialty(request.getMedicalSpecialty());
        if (request.getGender() != null)
            doctor.setGender(request.getGender());
        if (request.getDepartment() != null)
            doctor.setDepartment(request.getDepartment());
        if (request.getLanguagesSpoken() != null)
            doctor.setLanguagesSpoken(request.getLanguagesSpoken());
        if (request.getInternalCode() != null)
            doctor.setInternalCode(request.getInternalCode());
        if (request.getContractType() != null)
            doctor.setContractType(request.getContractType());
        if (request.getStatus() != null)
            doctor.setStatus(request.getStatus());
        if (request.getBiography() != null)
            doctor.setBiography(request.getBiography());
        if (request.getMedicalActsPerformed() != null)
            doctor.setMedicalActsPerformed(request.getMedicalActsPerformed());
        if (request.getEmail() != null)
            doctor.setEmail(request.getEmail());
        if (request.getPhoneNumber() != null)
            doctor.setPhoneNumber(request.getPhoneNumber());
        if (request.getLicenseNumber() != null)
            doctor.setLicenseNumber(request.getLicenseNumber());

        Doctor updatedDoctor = doctorRepository.save(doctor);
        log.info("Doctor updated successfully: {}", updatedDoctor.getId());

        return mapToResponse(updatedDoctor);
    }

    @Transactional(readOnly = true)
    public DoctorResponse getDoctorById(Long id) {
        log.info("Fetching doctor with ID: {}", id);
        Doctor doctor = doctorRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Doctor not found with ID: " + id));
        return mapToResponse(doctor);
    }

    @Transactional(readOnly = true)
    public List<DoctorResponse> getAllDoctors() {
        log.info("Fetching all doctors");
        return doctorRepository.findAll().stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<DoctorResponse> getDoctorsBySpecialty(String specialty) {
        log.info("Fetching doctors by specialty: {}", specialty);
        return doctorRepository.findByMedicalSpecialty(specialty).stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<DoctorResponse> getDoctorsByDepartment(String department) {
        log.info("Fetching doctors by department: {}", department);
        return doctorRepository.findByDepartment(department).stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<DoctorResponse> getAvailableDoctors() {
        log.info("Fetching available doctors");
        return doctorRepository.findAvailableDoctors().stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<DoctorResponse> getAvailableDoctorsBySpecialty(String specialty) {
        log.info("Fetching available doctors by specialty: {}", specialty);
        return doctorRepository.findAvailableDoctorsBySpecialty(specialty).stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<String> getAllSpecialties() {
        log.info("Fetching all specialties");
        return doctorRepository.findAllSpecialties();
    }

    @Transactional(readOnly = true)
    public List<String> getAllDepartments() {
        log.info("Fetching all departments");
        return doctorRepository.findAllDepartments();
    }

    @Transactional
    public void deleteDoctor(Long id) {
        log.info("Deleting doctor with ID: {}", id);
        Doctor doctor = doctorRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Doctor not found with ID: " + id));

        // Soft delete - set status to inactive instead of actual deletion
        doctor.setStatus(DoctorStatus.RETIRED);
        doctorRepository.save(doctor);
        log.info("Doctor soft-deleted successfully: {}", id);
    }

    private DoctorResponse mapToResponse(Doctor doctor) {
        return DoctorResponse.builder()
                .id(doctor.getId())
                .firstName(doctor.getFirstName())
                .lastName(doctor.getLastName())
                .medicalSpecialty(doctor.getMedicalSpecialty())
                .gender(doctor.getGender())
                .department(doctor.getDepartment())
                .languagesSpoken(doctor.getLanguagesSpoken())
                .internalCode(doctor.getInternalCode())
                .contractType(doctor.getContractType())
                .status(doctor.getStatus())
                .biography(doctor.getBiography())
                .medicalActsPerformed(doctor.getMedicalActsPerformed())
                .email(doctor.getEmail())
                .phoneNumber(doctor.getPhoneNumber())
                .licenseNumber(doctor.getLicenseNumber())
                .createdAt(doctor.getCreatedAt())
                .updatedAt(doctor.getUpdatedAt())
                .build();
    }
}
