package com.xjrsoft.module.base.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.model.result.RT;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.base.dto.AddBaseClassCourseDto;
import com.xjrsoft.module.base.dto.BaseClassCourseListDto;
import com.xjrsoft.module.base.dto.BaseClassCoursePageDto;
import com.xjrsoft.module.base.dto.ClassCourseReuseDto;
import com.xjrsoft.module.base.dto.UpdateBaseClassCourseDto;
import com.xjrsoft.module.base.entity.BaseClass;
import com.xjrsoft.module.base.entity.BaseClassCourse;
import com.xjrsoft.module.base.entity.BaseCourseSubject;
import com.xjrsoft.module.base.entity.BaseSemester;
import com.xjrsoft.module.base.entity.ClassCourseTextbook;
import com.xjrsoft.module.base.entity.CourseBookInfo;
import com.xjrsoft.module.base.service.IBaseClassCourseService;
import com.xjrsoft.module.base.service.impl.BaseCourseSubjectServiceImpl;
import com.xjrsoft.module.base.vo.BaseClassCourseExportListVo;
import com.xjrsoft.module.base.vo.BaseClassCourseListVo;
import com.xjrsoft.module.base.vo.BaseClassCoursePageVo;
import com.xjrsoft.module.base.vo.BaseClassCourseVo;
import com.xjrsoft.module.textbook.entity.Textbook;
import com.xjrsoft.module.textbook.service.impl.TextbookServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @title: 班级课程
 * @Author brealinxx
 * @Date: 2024-06-04
 * @Version 1.0
 */
@RestController
@RequestMapping("/base" + "/baseClassCourse")
@Api(value = "/base" + "/baseClassCourse", tags = "班级课程代码")
@AllArgsConstructor
public class BaseClassCourseController {


    private static final Logger log = LoggerFactory.getLogger(BaseClassCourseController.class);
    private final IBaseClassCourseService baseClassCourseService;
    private final BaseCourseSubjectServiceImpl baseCourseSubjectServiceImpl;
    private final TextbookServiceImpl textbookServiceImpl;

    @GetMapping(value = "/page")
    @ApiOperation(value = "班级课程列表(分页)")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<PageOutput<BaseClassCoursePageVo>> page(@Valid BaseClassCoursePageDto dto) {
        if(dto.getSemester() == null || dto.getSemester() == 0){
            Page<BaseClassCoursePageVo> page = new Page<>();
            page.setRecords(new ArrayList<>());
            return RT.ok(ConventPage.getPageOutput(page, BaseClassCoursePageVo.class));
        }
        Page<BaseClassCoursePageVo> page = baseClassCourseService.getPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
        PageOutput<BaseClassCoursePageVo> pageOutput = ConventPage.getPageOutput(page, BaseClassCoursePageVo.class);
        return RT.ok(pageOutput);
    }

    @GetMapping(value = "/list")
    @ApiOperation(value = "单个班级班级课程列表")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<List<BaseClassCourseListVo>> page(@Valid BaseClassCourseListDto dto) {
        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
        baseClassCourseMPJLambdaWrapper
                .select(BaseClassCourse::getCourseId)
                .selectAs(BaseClass::getName, BaseClassCourseListVo::getClassIdCn)
                .selectAs(BaseCourseSubject::getName, BaseClassCourseListVo::getCourseIdCn)
                .selectAs(Textbook::getBookName, BaseClassCourseListVo::getTextbookIdCn)
                .selectAs(BaseSemester::getName, BaseClassCourseListVo::getBaseSemesterIdCn)
                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseListVo.class).contains(x.getProperty()))
                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassCourse::getClassId)
                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassCourse::getBaseSemesterId)
                .eq(dto.getBaseSemesterId() != null && dto.getBaseSemesterId() > 0, BaseClassCourse::getBaseSemesterId, dto.getBaseSemesterId())
                .eq(dto.getClassId() != null && dto.getClassId() > 0, BaseClassCourse::getClassId, dto.getClassId())
                ;
        List<BaseClassCourseListVo> baseClassCourseListVoList = baseClassCourseService.selectJoinList(BaseClassCourseListVo.class, baseClassCourseMPJLambdaWrapper);
        return RT.ok(baseClassCourseListVoList);
    }

    @GetMapping("/getSemesterTree")
    @ApiOperation("获取年级树结构")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<Map<String, Map<String, Object>>> semesterTree() {
        Map<String, Map<String, Object>> tree = baseClassCourseService.getSemesterTree();
        return RT.ok(tree);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "根据id查询班级课程信息")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<BaseClassCourseVo> info(@RequestParam Long id) {
        BaseClassCourse baseClassCourse = baseClassCourseService.getById(id);
        if (baseClassCourse == null) {
            return RT.error("找不到此数据！");
        }
        return RT.ok(BeanUtil.toBean(baseClassCourse, BaseClassCourseVo.class));
    }

    @GetMapping("/getAllCoursesAndTextbooks")
    @ApiOperation(value = "获取所有课程教材")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<List<CourseBookInfo>> getAllCoursesAndTextbooks(@RequestParam(required = false) Long[] classIds, @RequestParam(required = false) Long subjectGroupId, @RequestParam(required = false) Long semester) {
        List<CourseBookInfo> data = baseClassCourseService.getAllCourseBook(classIds, subjectGroupId, semester);
        return RT.ok(data);
    }

    @GetMapping("/getAllSelectedCoursesAndTextbooks")
    @ApiOperation(value = "获取所有以选择课程教材")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<List<CourseBookInfo>> getAllSelectedCoursesAndTextbooks(@RequestParam(required = false) Long[] classIds, @RequestParam(required = false) Long semester) {
        List<CourseBookInfo> data = baseClassCourseService.getSelectedCourseBook(classIds, semester);
        return RT.ok(data);
    }

    @PostMapping("/updateAddCoursesAndTextbooks")
    @ApiOperation(value = "更新增加课程教材")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<Boolean> updateAddCoursesAndTextbooks(@Valid @RequestBody ClassCourseTextbook dto) {
        return RT.ok(baseClassCourseService.updateAddCourseBook(dto));
    }

    @PostMapping("/updateRemoveCoursesAndTextbooks")
    @ApiOperation(value = "更新减少课程教材")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<Boolean> updateRemoveCoursesAndTextbooks(@Valid ClassCourseTextbook list) {
        boolean isSuccess = true;
        for (Long classId : list.getClassIds()) {
            for (Long i = 0L; i < list.getCourseId().length; i++) {
                baseClassCourseService.updateRemoveCourseBook(classId, list.getCourseId()[Math.toIntExact(i)], list.getTextbookId()[Math.toIntExact(i)]);
            }
        }
        return RT.ok(isSuccess);
    }

    @PostMapping("/insertClassCourseTextbookCombinations")
    @ApiOperation(value = "复用课程教材")
    @SaCheckPermission("baseclasscourse:detail")
    public RT<Boolean> insertClassCourseTextbookCombinations(@Valid @RequestBody ClassCourseReuseDto dto) {
//        baseClassCourseService.markExistingRecordsAsDeleted(newClassId, sourceClassId);
        return RT.ok(baseClassCourseService.duplicateCourseBook(dto));
    }

    @PostMapping
    @ApiOperation(value = "新增班级课程")
    @SaCheckPermission("baseclasscourse:add")
    public RT<Boolean> add(@Valid @RequestBody AddBaseClassCourseDto dto) {
        BaseClassCourse baseClassCourse = BeanUtil.toBean(dto, BaseClassCourse.class);
        boolean isSuccess = baseClassCourseService.save(baseClassCourse);
        return RT.ok(isSuccess);
    }

    @PutMapping
    @ApiOperation(value = "修改班级课程")
    @SaCheckPermission("baseclasscourse:edit")
    public RT<Boolean> update(@Valid @RequestBody UpdateBaseClassCourseDto dto) {

        BaseClassCourse baseClassCourse = BeanUtil.toBean(dto, BaseClassCourse.class);
        return RT.ok(baseClassCourseService.updateById(baseClassCourse));

    }

    @DeleteMapping
    @ApiOperation(value = "删除班级课程")
    @SaCheckPermission("baseclasscourse:delete")
    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids) {
        return RT.ok(baseClassCourseService.removeBatchByIds(ids));

    }

    @PostMapping("/import")
    @ApiOperation(value = "导入")
    public RT<Boolean> importData(@RequestParam MultipartFile file) throws IOException {
        List<BaseClassCoursePageVo> savedDataList = EasyExcel.read(file.getInputStream()).headRowNumber(3).head(BaseClassCoursePageVo.class).sheet().doReadSync();

        List<BaseClassCourse> baseClassCourses = new ArrayList<>();
        List<String> duplicateLogs = new ArrayList<>();
        List<String> errorLogs = new ArrayList<>();

        for (BaseClassCoursePageVo vo : savedDataList) {
            try {
                Long classId = Long.parseLong(baseClassCourseService.GetClassIdByName(vo.getClassName()).toString());
                Long courseId = Long.parseLong(baseClassCourseService.GetCourseIdByName(vo.getCourseName()).toString());
                Long textbookId = Long.parseLong(baseClassCourseService.GetTextbookIdByName(vo.getTextbookName()).toString());
                Long baseSemesterId = Long.parseLong(baseClassCourseService.GetBaseSemesterIdByName(vo.getSemester()).toString());

                if (baseClassCourseService.checkExits(classId, courseId, textbookId)) {
                    duplicateLogs.add(String.format("[输入的信息重复添加] 班级: %s, 课程: %s, 教材: %s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName()));
                    continue;
                }

                if (classId != null && courseId != null && textbookId != null && baseSemesterId != null) {
                    BaseClassCourse baseClassCourse = new BaseClassCourse();
                    baseClassCourse.setClassId(classId);
                    baseClassCourse.setCourseId(courseId);
                    baseClassCourse.setTextbookId(textbookId);
                    baseClassCourse.setCreateDate(new Date());
                    baseClassCourse.setDeleteMark(0);
                    baseClassCourse.setBaseSemesterId(baseSemesterId);
                    baseClassCourses.add(baseClassCourse);
                }
            } catch (NumberFormatException e) {
                errorLogs.add(String.format("[无法解析输入的信息] 班级: %s, 班级: %s, 教材: %s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName()));
            } catch (Exception e) {
                errorLogs.add(String.format("[意外错误（检查输入的名称是否正确且存在，输入错误可能返回 null）] 班级: %s, 课程: %s, 教材: %s - 错误信息：%s", vo.getClassName(), vo.getCourseName(), vo.getTextbookName(), e.getMessage()));
            }
        }

        Boolean result = baseClassCourseService.saveBatch(baseClassCourses);

        if (!duplicateLogs.isEmpty() || !errorLogs.isEmpty()) {
            String detailedMessage = String.format("[导入完成但存在问题] 问题: %s. 其他错误: %s", String.join("; ", duplicateLogs), String.join("; ", errorLogs));
            return RT.error(400, detailedMessage);
        }

        return RT.ok(result);
    }

    @GetMapping("/export")
    @ApiOperation(value = "导出")
    public ResponseEntity<byte[]> exportData() {
        MPJLambdaWrapper<BaseClassCourse> baseClassCourseMPJLambdaWrapper = new MPJLambdaWrapper<>();
        baseClassCourseMPJLambdaWrapper
                .select(BaseClassCourse::getCourseId)
                .selectAs(BaseClass::getName, BaseClassCourseExportListVo::getClassIdCn)
                .selectAs(BaseCourseSubject::getName, BaseClassCourseExportListVo::getCourseIdCn)
                .selectAs(Textbook::getBookName, BaseClassCourseExportListVo::getTextbookIdCn)
                .selectAs(BaseSemester::getName, BaseClassCourseExportListVo::getBaseSemesterIdCn)
                .select(BaseClassCourse.class, x -> VoToColumnUtil.fieldsToColumns(BaseClassCourseExportListVo.class).contains(x.getProperty()))
                .leftJoin(BaseClass.class, BaseClass::getId, BaseClassCourse::getClassId)
                .leftJoin(BaseCourseSubject.class, BaseCourseSubject::getId, BaseClassCourse::getCourseId)
                .leftJoin(Textbook.class, Textbook::getId, BaseClassCourse::getTextbookId)
                .leftJoin(BaseSemester.class, BaseSemester::getId, BaseClassCourse::getBaseSemesterId)
        ;

        List<BaseClassCourseExportListVo> customerList = baseClassCourseService.selectJoinList(BaseClassCourseExportListVo.class, baseClassCourseMPJLambdaWrapper);
        ByteArrayOutputStream bot = new ByteArrayOutputStream();
        EasyExcel.write(bot, BaseClassCourseExportListVo.class).automaticMergeHead(false).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(customerList);

        return RT.fileStream(bot.toByteArray(), "BaseClassCourse" + ExcelTypeEnum.XLSX.getValue());
    }
}