package com.magistr.app.controller;

import com.magistr.app.config.auth.RequireRoles;
import com.magistr.app.dto.CreateDepartmentRequest;
import com.magistr.app.dto.DepartmentResponse;
import com.magistr.app.model.Department;
import com.magistr.app.model.LifecycleEntity;
import com.magistr.app.model.Role;
import com.magistr.app.repository.DepartmentRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/departments")
@RequireRoles({Role.ADMIN})
public class DepartmentController {

    private static final Logger logger = LoggerFactory.getLogger(DepartmentController.class);

    private final DepartmentRepository departmentRepository;

    public DepartmentController(DepartmentRepository departmentRepository) {
        this.departmentRepository = departmentRepository;
    }

    @GetMapping
    @RequireRoles({Role.ADMIN, Role.EDUCATION_OFFICE, Role.DEPARTMENT, Role.SCHEDULE_VIEWER})
    public List<Department> getAllDepartments(@RequestParam(defaultValue = "false") boolean includeArchived) {
        logger.info("Получен запрос на получение списка кафедр");
        try {
            List<Department> departments = includeArchived
                    ? departmentRepository.findAll()
                    : departmentRepository.findByStatusNot(LifecycleEntity.STATUS_ARCHIVED);
            List<Department> response = departments.stream()
                .map( d -> new Department(
                    d.getId(),
                    d.getDepartmentName(),
                    d.getDepartmentCode()
                ))
                .toList();
            logger.info("Получено {} кафедр", response.size());
            return response;
        } catch (Exception e) {
            logger.error("Ошибка при получении списка кафедр: {}", e.getMessage(), e);
            throw e;
        }
    }

    @PostMapping
    public ResponseEntity<?> createDepartment(@RequestBody CreateDepartmentRequest request) {
        logger.info("Получен запрос на создание кафедры: name = {}, code = {}", request.getDepartmentName(), request.getDepartmentCode());

        try {
            if (request.getDepartmentName() == null || request.getDepartmentName().isBlank()){
                String errorMessage = "Название кафедры обязательно";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }
            if (departmentRepository.findByDepartmentName(request.getDepartmentName().trim()).isPresent()) {
                String errorMessage = "Кафедра с таким названием уже существует";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }
            if (request.getDepartmentCode() == null || request.getDepartmentCode() == 0) {
                String errorMessage = "Код кафедры обязателен";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }
            if (departmentRepository.findByDepartmentCode(request.getDepartmentCode()).isPresent()) {
                String errorMessage = "Кафедра с таким кодом уже существует";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }

            Department department = new Department();
            department.setDepartmentName(request.getDepartmentName());
            department.setDepartmentCode(request.getDepartmentCode());
            departmentRepository.save(department);

            logger.info("Кафедра успешно создана с ID: {}", department.getId());

            return ResponseEntity.ok(
                    new DepartmentResponse(
                            department.getId(),
                            department.getDepartmentName(),
                            department.getDepartmentCode()
                    )
            );
        } catch (Exception e) {
            logger.error("Ошибка при создании кафедры", e);
            throw e;
        }
    }

    @PutMapping("/{id}")
    public ResponseEntity<?> updateDepartment(@PathVariable Long id, @RequestBody CreateDepartmentRequest request) {
        logger.info("Получен запрос на обновление кафедры с ID: {}", id);

        Department department = departmentRepository.findById(id).orElse(null);
        if (department == null) {
            logger.info("Кафедра с ID - {} не найдена", id);
            return ResponseEntity.notFound().build();
        }

        try {
            if (request.getDepartmentName() == null || request.getDepartmentName().isBlank()) {
                String errorMessage = "Название кафедры обязательно";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }
            if (request.getDepartmentCode() == null || request.getDepartmentCode() == 0) {
                String errorMessage = "Код кафедры обязателен";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }

            String departmentName = request.getDepartmentName().trim();
            if (departmentRepository.findByDepartmentName(departmentName)
                    .filter(existing -> !existing.getId().equals(id))
                    .isPresent()) {
                String errorMessage = "Кафедра с таким названием уже существует";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }
            if (departmentRepository.findByDepartmentCode(request.getDepartmentCode())
                    .filter(existing -> !existing.getId().equals(id))
                    .isPresent()) {
                String errorMessage = "Кафедра с таким кодом уже существует";
                logger.error("Ошибка валидации: {}", errorMessage);
                return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
            }

            department.setDepartmentName(departmentName);
            department.setDepartmentCode(request.getDepartmentCode());
            departmentRepository.save(department);

            logger.info("Кафедра с ID - {} успешно обновлена", id);
            return ResponseEntity.ok(new DepartmentResponse(
                    department.getId(),
                    department.getDepartmentName(),
                    department.getDepartmentCode()
            ));
        } catch (Exception e) {
            logger.error("Ошибка при обновлении кафедры с ID - {}", id, e);
            throw e;
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteDepartment(@PathVariable Long id) {
        logger.info("Получен запрос на удаление кафедры с ID: {}", id);
        Department department = departmentRepository.findById(id).orElse(null);
        if (department == null) {
            logger.info("Кафедра с ID - {} не найдена", id);
            return ResponseEntity.notFound().build();
        }
        department.archive("Кафедра архивирована");
        departmentRepository.save(department);
        logger.info("Кафедра с ID - {} успешно архивирована", id);
        return ResponseEntity.ok(Map.of("message", "Кафедра архивирована"));
    }

    @PostMapping("/{id}/restore")
    public ResponseEntity<?> restoreDepartment(@PathVariable Long id) {
        Department department = departmentRepository.findById(id).orElse(null);
        if (department == null) {
            return ResponseEntity.notFound().build();
        }
        department.restore();
        departmentRepository.save(department);
        return ResponseEntity.ok(new DepartmentResponse(
                department.getId(),
                department.getDepartmentName(),
                department.getDepartmentCode()
        ));
    }
}
