package com.hotwj.platform.securityManagement.training.controller;

import com.hotwj.platform.securityManagement.training.domain.bo.HotTrainingBo;
import com.hotwj.platform.securityManagement.training.domain.dto.RegisterVerifyDto;
import com.hotwj.platform.securityManagement.training.domain.vo.HotTrainingVo;
import com.hotwj.platform.securityManagement.training.service.IHotTrainingAnnualRecordExportService;
import com.hotwj.platform.securityManagement.training.service.IHotTrainingService;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.bo.HotTrainingCourseConfigBo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.vo.HotTrainingCourseConfigVo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.service.IHotTrainingCourseConfigService;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.bo.HotTrainingParticipantAddBo;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.vo.TrainingParticipantStatVo;
import com.hotwj.platform.securityManagement.trainingParticipant.service.IHotTrainingParticipantService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.core.BaseController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 安全教育培训-培训主
 *
 * @author shihongwei
 * @date 2025-12-17
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/securityManagement/training")
@Tag(name = "安全教育培训", description = "安全教育培训-培训主管理")
public class HotTrainingController extends BaseController {

    private static final String VERIFY_OSS_KEY_PREFIX = "verify:oss:";
    private static final Duration VERIFY_OSS_TTL = Duration.ofDays(7);

    private final IHotTrainingService hotTrainingService;
    private final IHotTrainingParticipantService hotTrainingParticipantService;
    private final IHotTrainingCourseConfigService hotTrainingCourseConfigService;
    private final IHotTrainingAnnualRecordExportService hotTrainingAnnualRecordExportService;

    /**
     * 查询安全教育培训-培训主列表
     */
    //@SaCheckPermission("securityManagement:training:list")
    @GetMapping("/list")
    @Operation(summary = "查询安全教育培训-培训主列表")
    public TableDataInfo<HotTrainingVo> list(HotTrainingBo bo, PageQuery pageQuery) {
        TableDataInfo<HotTrainingVo> page = hotTrainingService.queryPageList(bo, pageQuery);
        List<HotTrainingVo> rows = page.getRows();
        if (rows == null || rows.isEmpty()) {
            return page;
        }
        List<Long> trainingIds = rows.stream()
                .map(HotTrainingVo::getId)
                .collect(Collectors.toList());
        List<TrainingParticipantStatVo> stats = hotTrainingParticipantService.queryTrainingParticipantStats(trainingIds);
        if (stats == null || stats.isEmpty()) {
            for (HotTrainingVo vo : rows) {
                vo.setTotalCount(0L);
                vo.setPassedCount(0L);
                vo.setCompleteCount(0L);
                vo.setIncompleteCount(0L);
                vo.setPendingReviewCount(0L);
            }
            return page;
        }
        Map<Long, TrainingParticipantStatVo> statMap = stats.stream()
                .collect(Collectors.toMap(TrainingParticipantStatVo::getTrainingId, Function.identity()));
        for (HotTrainingVo vo : rows) {
            TrainingParticipantStatVo stat = statMap.get(vo.getId());
            if (stat == null) {
                vo.setTotalCount(0L);
                vo.setPassedCount(0L);
                vo.setIncompleteCount(0L);
                vo.setPendingReviewCount(0L);
                vo.setCompleteCount(0L);
            } else {
                vo.setTotalCount(stat.getTotalCount());
                vo.setPassedCount(stat.getPassedCount());
                vo.setIncompleteCount(stat.getIncompleteCount());
                vo.setPendingReviewCount(stat.getPendingReviewCount());
                vo.setCompleteCount(stat.getCompleteCount());
            }
        }
        return page;
    }

    @PostMapping("/registerVerify")
    @Operation(summary = "注册核验数据")
    public R<Boolean> registerVerify(@RequestBody @Validated RegisterVerifyDto dto) {
        RedisUtils.setCacheObject(VERIFY_OSS_KEY_PREFIX + dto.getJsonOssId(), "1", VERIFY_OSS_TTL);
        if (dto.getResourceOssIds() != null) {
            for (String ossId : dto.getResourceOssIds()) {
                if (org.dromara.common.core.utils.StringUtils.isBlank(ossId)) {
                    continue;
                }
                RedisUtils.setCacheObject(VERIFY_OSS_KEY_PREFIX + ossId, "1", VERIFY_OSS_TTL);
            }
        }
        return R.ok(true);
    }

    /**
     * 导出安全教育培训-培训主列表
     */
    //@SaCheckPermission("securityManagement:training:export")
    @Log(title = "安全教育培训-培训主", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @Operation(summary = "导出安全教育培训-培训主列表")
    public void export(HotTrainingBo bo, HttpServletResponse response) {
        List<HotTrainingVo> list = hotTrainingService.queryList(bo);
        ExcelUtil.exportExcel(list, "安全教育培训-培训主", HotTrainingVo.class, response);
    }

    /**
     * 获取安全教育培训-培训主详细信息
     *
     * @param id 主键
     */
    //@SaCheckPermission("securityManagement:training:query")
    @GetMapping("/{id}")
    @Operation(summary = "获取安全教育培训-培训主详细信息")
    public R<HotTrainingVo> getInfo(@NotNull(message = "主键不能为空")
                                    @PathVariable Long id) {
        return R.ok(hotTrainingService.queryById(id));
    }

    /**
     * 新增安全教育培训-培训主
     */
    //@SaCheckPermission("securityManagement:training:add")
    @Log(title = "安全教育培训-培训主", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    @Operation(summary = "新增安全教育培训-培训主")
    public R<Void> add(@Validated(AddGroup.class) @RequestBody HotTrainingBo bo) {
        return toAjax(hotTrainingService.insertByBo(bo));
    }

    /**
     * 修改安全教育培训-培训主
     */
    //@SaCheckPermission("securityManagement:training:edit")
    @Log(title = "安全教育培训-培训主", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    @Operation(summary = "修改安全教育培训-培训主")
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody HotTrainingBo bo) {
        return toAjax(hotTrainingService.updateByBo(bo));
    }

    //@SaCheckPermission("securityManagement:training:add")
    @Log(title = "安全教育培训-培训主", businessType = BusinessType.OTHER)
    @RepeatSubmit()
    @PostMapping("/issue")
    @Operation(summary = "下发安全教育培训")
    public R<String> issue(
            @RequestParam Long trainingId,
            @RequestParam String companyIds
    ) {
        HotTrainingVo source = hotTrainingService.queryById(trainingId);
        if (source == null) {
            return R.fail("培训计划不存在");
        }
        if (StringUtils.isBlank(source.getIndustryType())) {
            return R.fail("下发失败：行业类型不能为空，请先完善培训计划");
        }
        if (source.getClassHours() == null) {
            return R.fail("下发失败：所需课时不能为空，请先完善培训计划");
        }
        if (StringUtils.isBlank(source.getPaperIds())) {
            return R.fail("下发失败：请先绑定试卷后再下发企业");
        }
        if (companyIds == null || companyIds.isBlank()) {
            return R.fail("企业ID列表不能为空");
        }
        HotTrainingCourseConfigBo sourceCourseBo = new HotTrainingCourseConfigBo();
        sourceCourseBo.setCompanyId(source.getCompanyId());
        sourceCourseBo.setTrainingId(source.getId());
        sourceCourseBo.setIsDeleted(0L);
        List<HotTrainingCourseConfigVo> sourceCourseConfigs = hotTrainingCourseConfigService.queryList(sourceCourseBo);
        if (sourceCourseConfigs == null || sourceCourseConfigs.isEmpty()) {
            return R.fail("下发失败：请先配置课程后再下发企业");
        }
        String[] parts = companyIds.split(",");
        int success = 0;
        int fail = 0;
        StringBuilder sb = new StringBuilder();
        for (String p : parts) {
            String s = p.trim();
            if (s.isEmpty()) continue;
            try {
                Long cid = Long.valueOf(s);
                HotTrainingBo bo = new HotTrainingBo();
                bo.setCompanyId(cid);
                bo.setPlanName(source.getPlanName());
                bo.setPersonType(source.getPersonType());
                bo.setStartTime(source.getStartTime());
                bo.setEndTime(source.getEndTime());
                bo.setClassHours(source.getClassHours());
                bo.setPaperIds(source.getPaperIds());
                bo.setTrainingLocation(source.getTrainingLocation());
                bo.setTeacherName(source.getTeacherName());
                bo.setPlanOwner("总部");
                bo.setRemark(source.getRemark());
                bo.setIsEnabled(source.getIsEnabled());
                bo.setIsMakeUp(source.getIsMakeUp());
                bo.setCourseIds(source.getCourseIds());
                bo.setTrainingType(source.getTrainingType());
                bo.setParticipantIds(source.getParticipantIds());
                bo.setAssessmentDetail(source.getAssessmentDetail());
                bo.setReviewFlow(source.getReviewFlow());
                bo.setMeetingType(source.getMeetingType());
                bo.setMeetingCategory(source.getMeetingCategory());
                bo.setRecorderId(source.getRecorderId());
                bo.setRecorderName(source.getRecorderName());
                bo.setFiles(source.getFiles());
                bo.setPhotos(source.getPhotos());
                bo.setIsIssued(1L);
                bo.setIsDeleted(0L);
                if (hotTrainingService.insertByBo(bo)) {
                    try {
                        copyTrainingCourseConfig(sourceCourseConfigs, cid, bo.getId());
                        success++;
                    } catch (Exception e) {
                        fail++;
                        sb.append("课程配置下发失败: ").append(cid).append(" -> ").append(e.getMessage()).append("\n");
                        if (bo.getId() != null) {
                            hotTrainingService.deleteWithValidByIds(List.of(bo.getId()), false);
                        }
                    }
                } else {
                    fail++;
                    sb.append("下发失败: ").append(cid).append("\n");
                }
            } catch (Exception e) {
                fail++;
                sb.append("下发异常: ").append(s).append(" -> ").append(e.getMessage()).append("\n");
            }
        }
        HotTrainingBo upd = new HotTrainingBo();
        upd.setId(trainingId);
        upd.setIsIssued(1L);
        try {
            hotTrainingService.updateByBo(upd);
        } catch (Exception ignored) {
        }
        return R.ok("成功下发: " + success + " 家; 失败: " + fail + " 家" + (sb.length() > 0 ? ("\n" + sb) : ""));
    }

    private void copyTrainingCourseConfig(List<HotTrainingCourseConfigVo> sourceCourseConfigs, Long companyId, Long trainingId) {
        if (sourceCourseConfigs == null || sourceCourseConfigs.isEmpty()) {
            return;
        }
        List<Long> insertedIds = new ArrayList<>();
        try {
            for (HotTrainingCourseConfigVo sourceCourseConfig : sourceCourseConfigs) {
                HotTrainingCourseConfigBo addBo = new HotTrainingCourseConfigBo();
                addBo.setCompanyId(companyId);
                addBo.setTrainingId(trainingId);
                addBo.setCourseName(sourceCourseConfig.getCourseName());
                addBo.setCourseId(sourceCourseConfig.getCourseId());
                addBo.setCourseBelong(sourceCourseConfig.getCourseBelong());
                addBo.setStudyDuration(sourceCourseConfig.getStudyDuration());
                addBo.setIsDeleted(0L);
                boolean inserted = hotTrainingCourseConfigService.insertByBo(addBo);
                if (!inserted) {
                    throw new IllegalStateException("课程插入失败");
                }
                if (addBo.getId() != null) {
                    insertedIds.add(addBo.getId());
                }
            }
        } catch (Exception e) {
            if (!insertedIds.isEmpty()) {
                hotTrainingCourseConfigService.deleteWithValidByIds(insertedIds, false);
            }
            throw new IllegalStateException("课程配置复制失败", e);
        }
    }

    /**
     * 删除安全教育培训-培训主
     *
     * @param ids 主键串
     */
    //@SaCheckPermission("securityManagement:training:remove")
    @Log(title = "安全教育培训-培训主", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    @Operation(summary = "删除安全教育培训-培训主")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable Long[] ids) {
        return toAjax(hotTrainingService.deleteWithValidByIds(List.of(ids), true));
    }

    /**
     * 添加培训参与人员
     */
    //@SaCheckPermission("securityManagement:training:add")
    @Log(title = "安全教育培训-培训主表", businessType = BusinessType.INSERT)
    @PostMapping("/addParticipants")
    @Operation(
            summary = "添加培训参与人员",
            description = "按人员类型批量添加参与者：type=driver(驾驶员) 或 manager(管理员)。"
                    + "当人员已存在且 is_deleted=1 时将恢复为 0；同步初始化/恢复汇总宽表（hot_training_archive_summary）；"
                    + "根据人员类型发送系统通知。"
    )
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "操作成功", content = @Content(schema = @Schema(implementation = Void.class))),
            @ApiResponse(responseCode = "400", description = "请求参数错误", content = @Content)
    })
    public R<Void> addParticipants(
            @Validated
            @RequestBody
            @io.swagger.v3.oas.annotations.parameters.RequestBody(
                description = "添加参与人员请求体",
                required = true,
                content = @Content(
                        mediaType = "application/json",
                        schema = @Schema(implementation = HotTrainingParticipantAddBo.class),
                        examples = @ExampleObject(
                                name = "示例",
                                value = """
                                        {
                                          "trainingId": 123,
                                          "personList": [
                                            { "type": "driver", "ids": "10001,10002" },
                                            { "type": "manager", "ids": "20001" }
                                          ]
                                        }
                                        """
                        )
                )
            )
            HotTrainingParticipantAddBo bo
    ) {
        return toAjax(hotTrainingParticipantService.addParticipants(bo));
    }

    /**
     * 导出个人年度培训记录（单人导出Excel，多人导出ZIP）
     */
    @PostMapping("/exportPersonalAnnualRecord")
    @Operation(summary = "导出个人年度培训记录")
    public void exportPersonalAnnualRecord(@RequestParam String driverId,
                                           @RequestParam(required = false) Integer year,
                                           @RequestParam(required = false) String trainingType,
                                           HttpServletResponse response) {
        hotTrainingAnnualRecordExportService.exportPersonalAnnualRecord(driverId, year, trainingType, response);
    }
}
