package rd.controller.course;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.net.URLEncodeUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletResponse;
import rd.data.code.ServiceCode;
import rd.data.dto.FileByteDataWrapper;
import rd.data.dto.course.CourseDTO;
import rd.data.dto.course.CourseNameDTO;
import rd.data.db.CourseScheduleSelectionInfo;
import rd.data.db.table.Course;
import rd.data.db.table.StudentInfo;
import rd.data.model.response.PaginationWrapper;
import rd.data.model.response.Response;

import rd.service.course.CourseService;
import rd.service.course.CourseTeacherService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.List;

@RestController
@RequestMapping("/course")
public class CourseController {

    private final CourseService courseService;
    private final ObjectMapper objectMapper;
    private final CourseTeacherService courseTeacherService;

    public CourseController(CourseService courseService,
                            ObjectMapper objectMapper, CourseTeacherService courseTeacherService) {
        this.courseService = courseService;
        this.objectMapper = objectMapper;
        this.courseTeacherService = courseTeacherService;
    }

    @GetMapping("/list")
    public Response<PaginationWrapper<List<CourseDTO>>> list(
            @RequestParam(value = "page", required = false, defaultValue = "1") int page,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize
    ) {
        var result = courseService.list(page, pageSize);
        return Response.success(result);
    }

    @GetMapping("/list-names")
    public Response<PaginationWrapper<List<CourseNameDTO>>> listCourseName(
            @RequestParam(value = "page", required = false, defaultValue = "1") int page,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize
    ) {
        var result = courseService.listCourseName(page, pageSize);
        return Response.success(result);
    }

    @GetMapping("/info")
    public Response<CourseDTO> info(@RequestParam(value = "id") Long id) {
        var result = courseService.getCourseDTO(id);
        return Response.success(result);
    }

    @SaCheckRole(value = {"TEACHER", "ADMIN"}, mode = SaMode.OR)
    @GetMapping("/get-selected-students")
    public Response<List<CourseScheduleSelectionInfo>> getSelectedStudents(
            @RequestParam("course") Long courseId, @RequestParam("term") String term,
            @RequestParam(value = "page", required = false, defaultValue = "1") int page,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize
    ) {
        var courseScheduleSelectionInfoList = courseService.getSelectedStudentList(courseId, term);
        return Response.success(courseScheduleSelectionInfoList);
    }

    @SaCheckRole(value = {"TEACHER", "ADMIN"}, mode = SaMode.OR)
    @GetMapping("/get-not-selected-students")
    public Response<List<StudentInfo>> getNotSelectedStudents(
            @RequestParam("course") Long courseId, @RequestParam("term") String term,
            @RequestParam(value = "page", required = false, defaultValue = "1") int page,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") int pageSize
    ) {
        var courseScheduleSelectionInfoList = courseService.getNotSelectStudentList(courseId, term);
        return Response.success(courseScheduleSelectionInfoList);
    }

    @SaCheckRole(value = {"TEACHER", "ADMIN"}, mode = SaMode.OR)
    @GetMapping("/export-students")
    public void exportSelectedStudents(@RequestParam("course") Long course,
                                       @RequestParam("term") String term,
                                       HttpServletResponse response
    ) throws IOException {
        if (course == null) {
            Response<String> responseData = Response.error(ServiceCode.ParamWrong);
            response.setContentType("application/json");
            response.getWriter().write(objectMapper.writeValueAsString(responseData));
            return;
        }

        var data = courseService.exportSelectedStudents(course, term);

        var filename = String.format("exported_students_%s_%s.xlsx", data.getFileName(), term);
        this.responseExcelFile(response, URLEncodeUtil.encodeAll(filename), data);
    }

    @SaCheckRole(value = {"TEACHER", "ADMIN"}, mode = SaMode.OR)
    @GetMapping("/export-not-select-students")
    public void exportNotSelectStudents(@RequestParam("course") Long course,
                               @RequestParam("term") String term,
                               HttpServletResponse response
    ) throws IOException {
        if (course == null) {
            Response<String> responseData = Response.error(ServiceCode.ParamWrong);
            response.setContentType("application/json");
            response.getWriter().write(objectMapper.writeValueAsString(responseData));
            return;
        }

        var data = courseService.exportNotSelectStudents(course, term);

        var filename = String.format("exported_not_select_students_%s_%s.xlsx", data.getFileName(), term);
        this.responseExcelFile(response, URLEncodeUtil.encodeAll(filename), data);
    }

    private void responseExcelFile(HttpServletResponse response,
                                   String filename, FileByteDataWrapper data
    ) throws IOException {
        if (data == null) {
            Response<String> responseData = Response.success("数据是空的");
            response.setContentType("application/json");
            response.getWriter().write(objectMapper.writeValueAsString(responseData));
            return;
        }

        response.setContentLength(data.getData().length);
        response.setContentType("application/octet-stream");

        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", filename));

        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");

        response.getOutputStream().write(data.getData());
    }

    @SaCheckRole(value = {"TEACHER", "ADMIN"}, mode = SaMode.OR)
    @GetMapping("/teacher-courses")
    public Response<List<CourseDTO>> getCourseForTeacher(@RequestParam(value = "teacher", required = false) Long teacher) {
        if (teacher == null) {
            teacher = StpUtil.getLoginIdAsLong();
        }

        var courseList = courseTeacherService.getCourseForTeacher(teacher);
        var courseDTOList = courseList.stream().map(CourseController::convert).toList();

        return Response.success(courseDTOList);
    }

    private static CourseDTO convert(Course course) {
        CourseDTO courseDTO = new CourseDTO();
        courseDTO.setId(course.getId());
        courseDTO.setName(course.getName());
        courseDTO.setCourseHours(course.getCourseHours());
        courseDTO.setSpringTerm(course.getSpringTerm());
        courseDTO.setExamRatio(course.getExamRatio());
        courseDTO.setDistribution(course.getDistribution());

        return courseDTO;
    }
}
