package com.magistr.app.controller;

import com.magistr.app.config.auth.AuthContext;
import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.dto.ScheduleOverrideDto;
import com.magistr.app.model.*;
import com.magistr.app.repository.*;
import com.magistr.app.service.ScheduleGeneratorService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/edu-office/schedule/overrides")
@RequireRoles({Role.ADMIN, Role.EDUCATION_OFFICE})
public class ScheduleOverrideController {

    private final ScheduleOverrideRepository scheduleOverrideRepository;
    private final ScheduleRuleSlotRepository scheduleRuleSlotRepository;
    private final TimeSlotRepository timeSlotRepository;
    private final ClassroomRepository classroomRepository;
    private final UserRepository userRepository;
    private final ScheduleGeneratorService scheduleGeneratorService;

    public ScheduleOverrideController(ScheduleOverrideRepository scheduleOverrideRepository,
                                      ScheduleRuleSlotRepository scheduleRuleSlotRepository,
                                      TimeSlotRepository timeSlotRepository,
                                      ClassroomRepository classroomRepository,
                                      UserRepository userRepository,
                                      ScheduleGeneratorService scheduleGeneratorService) {
        this.scheduleOverrideRepository = scheduleOverrideRepository;
        this.scheduleRuleSlotRepository = scheduleRuleSlotRepository;
        this.timeSlotRepository = timeSlotRepository;
        this.classroomRepository = classroomRepository;
        this.userRepository = userRepository;
        this.scheduleGeneratorService = scheduleGeneratorService;
    }

    @GetMapping
    public List<ScheduleOverrideDto> getAll() {
        return scheduleOverrideRepository.findAll().stream()
                .map(this::toDto)
                .toList();
    }

    @PostMapping
    public ResponseEntity<?> create(@RequestBody ScheduleOverrideDto request) {
        return save(null, request);
    }

    @PutMapping("/{id}")
    public ResponseEntity<?> update(@PathVariable Long id, @RequestBody ScheduleOverrideDto request) {
        if (!scheduleOverrideRepository.existsById(id)) {
            return ResponseEntity.notFound().build();
        }
        return save(id, request);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> delete(@PathVariable Long id) {
        if (!scheduleOverrideRepository.existsById(id)) {
            return ResponseEntity.notFound().build();
        }
        scheduleOverrideRepository.deleteById(id);
        scheduleGeneratorService.clearCache();
        return ResponseEntity.ok(Map.of("message", "Точечное изменение расписания удалено"));
    }

    private ResponseEntity<?> save(Long id, ScheduleOverrideDto request) {
        String validationError = validate(request);
        if (validationError != null) {
            return ResponseEntity.badRequest().body(Map.of("message", validationError));
        }

        ScheduleOverride override = id == null
                ? scheduleOverrideRepository
                        .findByBaseRuleSlotIdAndLessonDate(request.baseRuleSlotId(), request.lessonDate())
                        .orElseGet(ScheduleOverride::new)
                : scheduleOverrideRepository.findById(id).orElseGet(ScheduleOverride::new);

        override.setBaseRuleSlot(scheduleRuleSlotRepository.findById(request.baseRuleSlotId()).orElseThrow());
        override.setLessonDate(request.lessonDate());
        override.setAction(request.action());
        override.setNewTimeSlot(request.newTimeSlotId() == null ? null : timeSlotRepository.findById(request.newTimeSlotId()).orElse(null));
        override.setNewClassroom(request.newClassroomId() == null ? null : classroomRepository.findById(request.newClassroomId()).orElse(null));
        override.setNewTeacher(request.newTeacherId() == null ? null : userRepository.findById(request.newTeacherId()).orElse(null));
        override.setNewLessonFormat(clean(request.newLessonFormat()));
        override.setComment(clean(request.comment()));
        override.setCreatedBy(AuthContext.currentUserId());

        ScheduleOverride saved = scheduleOverrideRepository.save(override);
        scheduleGeneratorService.clearCache();
        return ResponseEntity.ok(toDto(saved));
    }

    private String validate(ScheduleOverrideDto request) {
        if (request == null) {
            return "Передайте данные изменения расписания";
        }
        if (request.baseRuleSlotId() == null || scheduleRuleSlotRepository.findById(request.baseRuleSlotId()).isEmpty()) {
            return "Базовый слот расписания не найден";
        }
        if (request.lessonDate() == null) {
            return "Дата пары обязательна";
        }
        if (request.action() == null || !List.of("MOVE", "CANCEL", "REPLACE").contains(request.action())) {
            return "Недопустимое действие изменения расписания";
        }
        if (request.newClassroomId() != null) {
            Classroom classroom = classroomRepository.findById(request.newClassroomId()).orElse(null);
            if (classroom == null || classroom.isArchivedRecord() || Boolean.FALSE.equals(classroom.getIsAvailable())) {
                return "Активная аудитория не найдена";
            }
        }
        if (request.newTeacherId() != null) {
            User teacher = userRepository.findById(request.newTeacherId()).orElse(null);
            if (teacher == null || teacher.getRole() != Role.TEACHER || teacher.isArchivedRecord()) {
                return "Активный преподаватель не найден";
            }
        }
        if (request.newTimeSlotId() != null && timeSlotRepository.findById(request.newTimeSlotId()).isEmpty()) {
            return "Временной слот не найден";
        }
        return null;
    }

    private ScheduleOverrideDto toDto(ScheduleOverride override) {
        return new ScheduleOverrideDto(
                override.getId(),
                override.getBaseRuleSlot().getId(),
                override.getLessonDate(),
                override.getAction(),
                override.getNewTimeSlot() == null ? null : override.getNewTimeSlot().getId(),
                override.getNewClassroom() == null ? null : override.getNewClassroom().getId(),
                override.getNewTeacher() == null ? null : override.getNewTeacher().getId(),
                override.getNewLessonFormat(),
                override.getComment(),
                override.getCreatedBy(),
                override.getCreatedAt()
        );
    }

    private String clean(String value) {
        return value == null || value.isBlank() ? null : value.trim();
    }
}
