package com.example.projectback.controllers;

import com.example.projectback.model.*;
import com.example.projectback.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@CrossOrigin(origins = "http://localhost:4200")
@RequestMapping("/subjects")
public class SubjectController {
    private final SubjectRepository subjectRepository;
    private final SubjectStudentRepository subjectStudentRepository;
    private final StudentRepository studentRepository;
    private final GradeRepository gradeRepository;
    private final UserRepository userRepository;

    @Autowired
    public SubjectController(SubjectRepository subjectRepository, SubjectStudentRepository subjectStudentRepository,
                             StudentRepository studentRepository, GradeRepository gradeRepository,
                             UserRepository userRepository) {
        this.subjectRepository = subjectRepository;
        this.subjectStudentRepository = subjectStudentRepository;
        this.studentRepository = studentRepository;
        this.gradeRepository = gradeRepository;
        this.userRepository = userRepository;
    }

    @GetMapping
    @PreAuthorize("hasRole('ADMIN')")
    public List<Subject> getAllSubjects() {
        return subjectRepository.findAll();
    }

    @GetMapping("/student/{id}")
    @PreAuthorize("hasRole('ADMIN') or hasRole('USER')")
    public List<Subject> getAllSubjectsForStudent(@PathVariable("id") Long studentID) {
        User user = userRepository.getById(studentID);
        Student student = studentRepository.getByEmail(user.getEmail());
        List<SubjectStudent> assoc = subjectStudentRepository.getAllByStudent(student);
        List<Subject> studentSubjects = new ArrayList<>();
        for (SubjectStudent subjectStudent: assoc) {
            Subject subject = subjectStudent.getSubject();
            List<SubjectStudent> newAssoc = new ArrayList<>();
            newAssoc.add(new SubjectStudent(subject, student));
            subject.setStudentsAssoc(newAssoc);
            studentSubjects.add(subject);
        }
        return studentSubjects;
    }

    @GetMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Subject> getSubject(@PathVariable("id") Long id) {
        Optional<Subject> subject = subjectRepository.findById(id);
        if (subject.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(subject.get(), HttpStatus.OK);
    }

    @PostMapping
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Subject> addSubject(@RequestBody Subject subject) {
        subjectRepository.save(subject);
        return new ResponseEntity<>(subject, HttpStatus.CREATED);
    }

    @PostMapping("/delete")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Changeset> deleteSubjects(@RequestBody Changeset changeset) {
        for (Long recId : changeset.getRecords()) {
            Optional<Subject> subject = subjectRepository.findById(recId);
            if (subject.isEmpty()) continue;
            List<SubjectStudent> subjectStudents = subjectStudentRepository.getAllBySubject(subject.get());
            List<Grade> grades = gradeRepository.getAllBySubjectID(subject.get().getId());
            List<Student> allStudents = studentRepository.findAll();
            for(Student student: allStudents) {
                student.getGrades().removeAll(grades);
                studentRepository.save(student);
            }
            subjectStudentRepository.deleteAll(subjectStudents);
            gradeRepository.deleteAll(grades);
            subjectRepository.delete(subject.get());
        }
        return new ResponseEntity<>(changeset, HttpStatus.OK);
    }

    @PatchMapping("/{id}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Subject> updatePartOfSubject(@RequestBody Map<String, Object> updates, @PathVariable("id") Long id) {
        Optional<Subject> subject = subjectRepository.findById(id);
        if (subject.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        partialUpdates(subject.get(), updates);
        return new ResponseEntity<>(subject.get(), HttpStatus.OK);
    }

    private void partialUpdates(Subject subject, Map<String, Object> updates) {
        if (updates.containsKey("name")) {
            subject.setName((String) updates.get("nane"));
        }
        if (updates.containsKey("studentAssoc")) {
            List<SubjectStudent> newStudents = subject.getStudentsAssoc();
            for (Integer studentId : (List<Integer>) updates.get("studentAssoc")) {
                Student student = this.studentRepository.getById(studentId.longValue());
                SubjectStudent newAssoc = new SubjectStudent(subject, student);
                this.subjectStudentRepository.save(newAssoc);
                newStudents.add(newAssoc);
            }
            subject.setStudentsAssoc(newStudents);
        }
        subjectRepository.save(subject);
    }

    @DeleteMapping("/{subjectID}/{studentID}")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<Subject> removeStudentFromSubject(@PathVariable("subjectID") Long subjectID, @PathVariable Long studentID) {
        Optional<Subject> subject = subjectRepository.findById(subjectID);
        Optional<Student> student = studentRepository.findById(studentID);
        if (subject.isEmpty() || student.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        SubjectStudent assoc = this.subjectStudentRepository.getByStudentAndSubject(student.get(), subject.get());
        subject.get().getStudentsAssoc().remove(assoc);
        this.subjectStudentRepository.delete(assoc);
        this.subjectRepository.save(subject.get());
        return new ResponseEntity<>(subject.get(), HttpStatus.OK);
    }
}
