package com.magistr.app.controller;

import com.magistr.app.config.auth.AuthContext;
import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.dto.ReviewTeacherCreationRequest;
import com.magistr.app.dto.TeacherCreationRequestResponse;
import com.magistr.app.dto.UserResponse;
import com.magistr.app.model.*;
import com.magistr.app.repository.DepartmentRepository;
import com.magistr.app.repository.TeacherCreationRequestRepository;
import com.magistr.app.repository.TeacherDepartmentAssignmentRepository;
import com.magistr.app.repository.UserRepository;
import com.magistr.app.service.BusinessTimeService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/teacher-requests")
@RequireRoles({Role.ADMIN})
public class TeacherCreationRequestController {

    private final TeacherCreationRequestRepository teacherCreationRequestRepository;
    private final UserRepository userRepository;
    private final DepartmentRepository departmentRepository;
    private final TeacherDepartmentAssignmentRepository teacherDepartmentAssignmentRepository;
    private final BCryptPasswordEncoder passwordEncoder;
    private final BusinessTimeService businessTime;

    public TeacherCreationRequestController(TeacherCreationRequestRepository teacherCreationRequestRepository,
                                            UserRepository userRepository,
                                            DepartmentRepository departmentRepository,
                                            TeacherDepartmentAssignmentRepository teacherDepartmentAssignmentRepository,
                                            BCryptPasswordEncoder passwordEncoder,
                                            BusinessTimeService businessTime) {
        this.teacherCreationRequestRepository = teacherCreationRequestRepository;
        this.userRepository = userRepository;
        this.departmentRepository = departmentRepository;
        this.teacherDepartmentAssignmentRepository = teacherDepartmentAssignmentRepository;
        this.passwordEncoder = passwordEncoder;
        this.businessTime = businessTime;
    }

    @GetMapping
    public List<TeacherCreationRequestResponse> getRequests(@RequestParam(required = false) TeacherCreationRequestStatus status) {
        return (status == null
                ? teacherCreationRequestRepository.findAllByOrderByCreatedAtDesc()
                : teacherCreationRequestRepository.findByStatusOrderByCreatedAtDesc(status))
                .stream()
                .map(this::toResponse)
                .toList();
    }

    @PostMapping("/{id}/approve")
    @Transactional
    public ResponseEntity<?> approve(@PathVariable Long id, @RequestBody ReviewTeacherCreationRequest review) {
        TeacherCreationRequest request = teacherCreationRequestRepository.findById(id).orElse(null);
        if (request == null) {
            return ResponseEntity.notFound().build();
        }
        if (request.getStatus() != TeacherCreationRequestStatus.PENDING) {
            return ResponseEntity.badRequest().body(Map.of("message", "Заявка уже обработана"));
        }
        if (review == null) {
            return ResponseEntity.badRequest().body(Map.of("message", "Данные одобрения обязательны"));
        }

        String username = firstNotBlank(review.getUsername(), request.getUsername());
        String fullName = firstNotBlank(review.getFullName(), request.getFullName());
        String jobTitle = firstNotBlank(review.getJobTitle(), request.getJobTitle(), "Не указано");
        if (username.length() > 50 || fullName.length() > 255 || jobTitle.length() > 255) {
            return ResponseEntity.badRequest().body(Map.of("message", "Проверьте длину полей преподавателя"));
        }
        if (review.getPassword() == null || review.getPassword().length() < 8) {
            return ResponseEntity.badRequest().body(Map.of("message", "Пароль преподавателя должен быть не короче 8 символов"));
        }
        if (userRepository.findByUsername(username).isPresent()) {
            return ResponseEntity.badRequest().body(Map.of("message", "Пользователь с таким логином уже существует"));
        }

        Long departmentId = review.getDepartmentId() == null ? request.getDepartment().getId() : review.getDepartmentId();
        Department department = departmentRepository.findById(departmentId).orElse(null);
        if (department == null || department.isArchivedRecord()) {
            return ResponseEntity.badRequest().body(Map.of("message", "Активная кафедра не найдена"));
        }

        User teacher = new User();
        teacher.setUsername(username);
        teacher.setPassword(passwordEncoder.encode(review.getPassword()));
        teacher.setRole(Role.TEACHER);
        teacher.setFullName(fullName);
        teacher.setJobTitle(jobTitle);
        teacher.setDepartmentId(department.getId());
        userRepository.save(teacher);

        TeacherDepartmentAssignment assignment = new TeacherDepartmentAssignment();
        assignment.setTeacher(teacher);
        assignment.setDepartment(department);
        assignment.setValidFrom(businessTime.today());
        assignment.setCreatedAt(businessTime.now());
        assignment.setPrimaryAssignment(true);
        assignment.setComment("Создан по заявке кафедры #" + request.getId());
        assignment.setCreatedBy(AuthContext.currentUserId());
        teacherDepartmentAssignmentRepository.save(assignment);

        request.setUsername(username);
        request.setFullName(fullName);
        request.setJobTitle(jobTitle);
        request.setDepartment(department);
        request.setStatus(TeacherCreationRequestStatus.APPROVED);
        request.setReviewedBy(AuthContext.currentUserId());
        request.setReviewedAt(businessTime.now());
        request.setReviewComment(trimToNull(review.getReviewComment()));
        request.setCreatedTeacherId(teacher.getId());
        teacherCreationRequestRepository.save(request);

        return ResponseEntity.ok(Map.of(
                "request", toResponse(request),
                "teacher", toUserResponse(teacher, department)
        ));
    }

    @PostMapping("/{id}/reject")
    public ResponseEntity<?> reject(@PathVariable Long id, @RequestBody(required = false) ReviewTeacherCreationRequest review) {
        TeacherCreationRequest request = teacherCreationRequestRepository.findById(id).orElse(null);
        if (request == null) {
            return ResponseEntity.notFound().build();
        }
        if (request.getStatus() != TeacherCreationRequestStatus.PENDING) {
            return ResponseEntity.badRequest().body(Map.of("message", "Заявка уже обработана"));
        }
        request.setStatus(TeacherCreationRequestStatus.REJECTED);
        request.setReviewedBy(AuthContext.currentUserId());
        request.setReviewedAt(businessTime.now());
        request.setReviewComment(trimToNull(review == null ? null : review.getReviewComment()));
        return ResponseEntity.ok(toResponse(teacherCreationRequestRepository.save(request)));
    }

    private TeacherCreationRequestResponse toResponse(TeacherCreationRequest request) {
        Department department = request.getDepartment();
        return new TeacherCreationRequestResponse(
                request.getId(),
                department == null ? null : department.getId(),
                department == null ? null : department.getDepartmentName(),
                request.getUsername(),
                request.getFullName(),
                request.getJobTitle(),
                request.getComment(),
                request.getStatus().name(),
                request.getRequestedBy(),
                request.getCreatedAt(),
                request.getReviewedBy(),
                request.getReviewedAt(),
                request.getReviewComment(),
                request.getCreatedTeacherId()
        );
    }

    private UserResponse toUserResponse(User user, Department department) {
        UserResponse response = new UserResponse(
                user.getId(),
                user.getUsername(),
                user.getRole().name(),
                user.getFullName(),
                user.getJobTitle(),
                department.getDepartmentName()
        );
        response.setDepartmentId(department.getId());
        response.setStatus(user.getStatus());
        return response;
    }

    private String firstNotBlank(String... values) {
        for (String value : values) {
            String normalized = trimToNull(value);
            if (normalized != null) {
                return normalized;
            }
        }
        return "";
    }

    private String trimToNull(String value) {
        if (value == null || value.isBlank()) {
            return null;
        }
        return value.trim();
    }
}
