package com.magistr.app.controller;

import com.magistr.app.config.auth.AuthContext;
import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.dto.TeacherSubjectResponse;
import com.magistr.app.model.Role;
import com.magistr.app.model.Subject;
import com.magistr.app.model.TeacherSubject;
import com.magistr.app.model.TeacherSubjectId;
import com.magistr.app.model.User;
import com.magistr.app.repository.SubjectRepository;
import com.magistr.app.repository.TeacherSubjectRepository;
import com.magistr.app.repository.UserRepository;
import com.magistr.app.service.TeacherDepartmentService;
import com.magistr.app.service.BusinessTimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/teacher-subjects")
@RequireRoles({Role.ADMIN, Role.DEPARTMENT})
public class TeacherSubjectController {

    private final TeacherSubjectRepository teacherSubjectRepository;
    private final UserRepository userRepository;
    private final SubjectRepository subjectRepository;
    private final TeacherDepartmentService teacherDepartmentService;
    private final BusinessTimeService businessTime;

    public TeacherSubjectController(TeacherSubjectRepository teacherSubjectRepository,
                                    UserRepository userRepository,
                                    SubjectRepository subjectRepository,
                                    TeacherDepartmentService teacherDepartmentService) {
        this(teacherSubjectRepository, userRepository, subjectRepository,
                teacherDepartmentService, BusinessTimeService.systemDefault());
    }

    @Autowired
    public TeacherSubjectController(TeacherSubjectRepository teacherSubjectRepository,
                                    UserRepository userRepository,
                                    SubjectRepository subjectRepository,
                                    TeacherDepartmentService teacherDepartmentService,
                                    BusinessTimeService businessTime) {
        this.teacherSubjectRepository = teacherSubjectRepository;
        this.userRepository = userRepository;
        this.subjectRepository = subjectRepository;
        this.teacherDepartmentService = teacherDepartmentService;
        this.businessTime = businessTime;
    }

    @GetMapping
    public List<TeacherSubjectResponse> getAll() {
        return teacherSubjectRepository.findAll().stream()
                .filter(ts -> canManage(ts.getUser(), ts.getSubject()))
                .map(ts -> new TeacherSubjectResponse(
                        ts.getUserId(),
                        ts.getUser().getUsername(),
                        ts.getSubjectId(),
                        ts.getSubject().getName()
                ))
                .toList();
    }

    @PostMapping
    public ResponseEntity<?> create(@RequestBody Map<String, Long> request) {
        Long userId = request.get("userId");
        Long subjectId = request.get("subjectId");

        if (userId == null || subjectId == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "userId и subjectId обязательны"));
        }
        User user = userRepository.findById(userId).orElse(null);
        if (user == null || user.getRole() != Role.TEACHER || user.isArchivedRecord()) {
            return ResponseEntity.badRequest().body(Map.of("message", "Преподаватель не найден"));
        }
        Subject subject = subjectRepository.findById(subjectId).orElse(null);
        if (subject == null || subject.isArchivedRecord()) {
            return ResponseEntity.badRequest().body(Map.of("message", "Дисциплина не найдена"));
        }
        if (!canManage(user, subject)) {
            return ResponseEntity.status(403).body(Map.of("message", "Кафедра может связывать только своих преподавателей и свои дисциплины"));
        }

        TeacherSubjectId id = new TeacherSubjectId(userId, subjectId);
        if (teacherSubjectRepository.existsById(id)) {
            return ResponseEntity.badRequest().body(Map.of("message", "Привязка уже существует"));
        }

        TeacherSubject ts = new TeacherSubject(userId, subjectId);
        teacherSubjectRepository.save(ts);

        return ResponseEntity.ok(Map.of("message", "Привязка создана"));
    }

    @DeleteMapping
    public ResponseEntity<?> delete(@RequestBody Map<String, Long> request) {
        Long userId = request.get("userId");
        Long subjectId = request.get("subjectId");

        if (userId == null || subjectId == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "userId и subjectId обязательны"));
        }

        TeacherSubjectId id = new TeacherSubjectId(userId, subjectId);
        TeacherSubject teacherSubject = teacherSubjectRepository.findById(id).orElse(null);
        if (teacherSubject == null) {
            return ResponseEntity.notFound().build();
        }
        if (!canManage(teacherSubject.getUser(), teacherSubject.getSubject())) {
            return ResponseEntity.status(403).body(Map.of("message", "Кафедра может удалять только свои привязки"));
        }
        teacherSubjectRepository.deleteById(id);
        return ResponseEntity.ok(Map.of("message", "Привязка удалена"));
    }

    private boolean canManage(User teacher, Subject subject) {
        var currentUser = AuthContext.getCurrentUser();
        if (currentUser == null || currentUser.role() == Role.ADMIN) {
            return true;
        }
        if (currentUser.role() != Role.DEPARTMENT) {
            return false;
        }
        Long departmentId = currentUser.departmentId();
        return departmentId != null
                && teacher != null
                && subject != null
                && teacherDepartmentService.hasAssignmentAtDate(
                        teacher.getId(),
                        departmentId,
                        businessTime.today()
                )
                && departmentId.equals(subject.getDepartmentId());
    }
}
