package org.fuseri.modulelanguageschool.lecture;

import jakarta.persistence.EntityNotFoundException;
import org.fuseri.model.dto.course.LanguageTypeDto;
import org.fuseri.model.dto.course.ProficiencyLevelDto;
import org.fuseri.model.dto.lecture.LectureCreateDto;
import org.fuseri.model.dto.lecture.LectureDto;
import org.fuseri.modulelanguageschool.course.CourseService;
import org.fuseri.modulelanguageschool.course.Language;
import org.fuseri.modulelanguageschool.course.ProficiencyLevel;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class LectureFacade {

    private final LectureService lectureService;

    private final UserService userService;
    private final LectureMapper lectureMapper;
    private final UserMapper userMapper;
    private final CourseService courseService;

    @Autowired
    public LectureFacade(LectureService lectureService, UserService userService, LectureMapper lectureMapper, UserMapper userMapper, CourseService courseService) {
        this.lectureService = lectureService;
        this.userService = userService;
        this.lectureMapper = lectureMapper;
        this.userMapper = userMapper;
        this.courseService = courseService;
    }

    @Transactional
    public LectureDto create(LectureCreateDto dto) {
        return lectureMapper.mapToDto(lectureService.save(lectureMapper.mapToLecture(dto, courseService)));
    }

    @Cacheable(cacheNames = "lecture")
    @Transactional(readOnly = true)
    public LectureDto findById(Long id) {
        return lectureMapper.mapToDto(lectureService.findById(id));
    }

    @Cacheable(cacheNames = "lectures")
    @Transactional(readOnly = true)
    public List<LectureDto> findAll(Long id) {
        return lectureMapper.mapToList(lectureService.findAllByCourse(id));
    }

    @Transactional
    public LectureDto update(Long id, LectureCreateDto dto) {
        return lectureMapper.mapToDto(lectureService.update(id, lectureMapper.mapToLecture(dto, courseService)));
    }

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

    @Cacheable(cacheNames = "lectures")
    public List<LectureDto> findAll(LanguageTypeDto lang) {
        return lectureMapper.mapToList(lectureService.findAll(Language.valueOf(lang.name())));
    }

    @Cacheable(cacheNames = "lectures")
    public List<LectureDto> findAll(LanguageTypeDto lang, ProficiencyLevelDto prof) {
        return lectureMapper.mapToList(lectureService.findAll(Language.valueOf(lang.name()), ProficiencyLevel.valueOf(prof.name())));
    }

    public LectureDto enrol(Long id, Long studentId) {
        var student = userService.find(studentId);
        return lectureMapper.mapToDto(lectureService.enrol(id, student));
    }

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

    public LectureDto expel(Long id, Long studentId) {
        var student = userService.find(studentId);
        return lectureMapper.mapToDto(lectureService.expel(id, student));
    }

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

    public LectureDto setLecturer(Long id, Long lecturerId) {
        var lecturer = userService.find(lecturerId);
        return lectureMapper.mapToDto(lectureService.setLecturer(id, lecturer));
    }
}
