package org.fuseri.modulelanguageschool.course;

import jakarta.persistence.EntityNotFoundException;
import org.fuseri.model.dto.course.CourseCreateDto;
import org.fuseri.model.dto.course.CourseDto;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.modulelanguageschool.user.UserMapper;
import org.fuseri.modulelanguageschool.user.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class CourseFacade {
    private final CourseService courseService;
    private final UserService userService;
    private final CourseMapper courseMapper;
    private final UserMapper userMapper;

    @Autowired
    public CourseFacade(CourseService courseService, UserService userService, CourseMapper courseMapper, UserMapper userMapper) {
        this.courseService = courseService;
        this.userService = userService;
        this.courseMapper = courseMapper;
        this.userMapper = userMapper;
    }

    @Transactional
    public CourseDto create(CourseCreateDto dto) {
        return courseMapper.mapToDto(courseService.save(courseMapper.mapToCourse(dto)));
    }

    @Cacheable(cacheNames = "course")
    @Transactional(readOnly = true)
    public CourseDto findById(Long id) {
        return courseMapper.mapToDto(courseService.findById(id));
    }

    @Transactional(readOnly = true)
    public Page<CourseDto> findAll(Pageable pageable) {
        return courseMapper.mapToPageDto(courseService.findAll(pageable));
    }

    @Transactional
    public CourseDto update(Long id, CourseCreateDto dto) {
        return courseMapper.mapToDto(courseService.update(id, courseMapper.mapToCourse(dto)));
    }

    @Transactional
    public void delete(Long id) {
        courseService.delete(id);
    }

    @Cacheable(cacheNames = "courses")
    public List<CourseDto> findAll(LanguageTypeDto lang) {
        return courseMapper.mapToList(courseService.findAll(Language.valueOf(lang.name())));
    }

    @Cacheable(cacheNames = "courses")
    public List<CourseDto> findAll(LanguageTypeDto lang, ProficiencyLevelDto prof) {
        return courseMapper.mapToList(courseService.findAll(Language.valueOf(lang.name()), ProficiencyLevel.valueOf(prof.name())));
    }

    public CourseDto enrol(Long id, Long studentId) {
        var student = userService.find(studentId);
        return courseMapper.mapToDto(courseService.enrol(id, student));
    }

    public CourseDto enrol(Long id, String email) {
        var student = userService.findUserByEmail(email)
                .orElseThrow(() -> new EntityNotFoundException("User with " + email + " email not found."));
        return courseMapper.mapToDto(courseService.enrol(id, student));
    }

    public CourseDto expel(Long id, Long studentId) {
        var student = userService.find(studentId);
        return courseMapper.mapToDto(courseService.expel(id, student));
    }

    public CourseDto expel(Long id, String email) {
        var student = userService.findUserByEmail(email)
                .orElseThrow(() -> new EntityNotFoundException("User with " + email + " email not found."));
        return courseMapper.mapToDto(courseService.expel(id, student));
    }
}
