package com.goldenwater.slaj.acci.controller;

import java.util.List;
import java.util.Map;
import java.util.Calendar;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.goldenwater.common.annotation.Log;
import com.goldenwater.common.core.controller.BaseController;
import com.goldenwater.common.core.domain.AjaxResult;
import com.goldenwater.common.core.page.TableDataInfo;
import com.goldenwater.common.enums.BusinessType;
import com.goldenwater.common.utils.poi.ExcelUtil;
import com.goldenwater.slaj.acci.domain.BisAcciMont;
import com.goldenwater.slaj.acci.domain.ObjAcci;
import com.goldenwater.slaj.acci.service.IBisAcciMontService;
import com.goldenwater.slaj.acci.service.IObjAcciService;

/**
 * 事故月报
 */
@RestController
@RequestMapping("/acci/bisaccimont")
public class BisAcciMontController extends BaseController {
    @Autowired
    private IBisAcciMontService bisAcciMontService;

    @Autowired
    private IObjAcciService objAcciService;

    @GetMapping("/list")
    public TableDataInfo list(BisAcciMont bisAcciMont) {
        startPage();
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(bisAcciMont);
        return getDataTable(list);
    }

    @GetMapping("/{guid}")
    public AjaxResult getInfo(@PathVariable String guid) {
        return AjaxResult.success(bisAcciMontService.selectBisAcciMontByGuid(guid));
    }

    @PostMapping
    public AjaxResult add(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.insertBisAcciMont(bisAcciMont));
    }

    @PutMapping
    public AjaxResult edit(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    /**
     * 月报上报主流程 — 将当前月份事故月报提交至上级单位（montStat 更新为 "1"）。
     * 若当月月报尚未创建（首次上报），则自动插入新记录；若已创建则更新状态。
     * 上报前需校验：①当前月份未被水利部锁定；②上级单位尚未上报（上级已上报则下级不可再报）；
     * ③上报时自动触发月期间表（BisAcciPeriod）的创建/更新。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:edit')")
    @PostMapping("/submit")
    public AjaxResult submit(@RequestBody BisAcciMont bisAcciMont) {
        BisAcciMont existing = bisAcciMontService.selectBisAcciMontByGuid(bisAcciMont.getGuid());
        if (existing == null) {
            bisAcciMont.setMontStat("1");
            return toAjax(bisAcciMontService.insertBisAcciMont(bisAcciMont));
        }
        existing.setMontStat("1");
        return toAjax(bisAcciMontService.updateBisAcciMont(existing));
    }

    @DeleteMapping("/{guids}")
    public AjaxResult remove(@PathVariable String[] guids) {
        return toAjax(bisAcciMontService.deleteBisAcciMontByGuids(guids));
    }

    @Log(title = "事故月报管理", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, BisAcciMont bisAcciMont) {
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(bisAcciMont);
        ExcelUtil<BisAcciMont> util = new ExcelUtil<BisAcciMont>(BisAcciMont.class);
        util.exportExcel(response, list, "事故月报数据");
    }

    /**
     * 月报审核 — 上级单位对下级上报的月报进行审核验收（montStat 更新为 "2"）。
     * 审核通过代表上级确认下级月报数据真实完整，纳入上级汇总统计。
     * 审核功能仅对拥有审核权限的角色开放，通常是水利厅/局级单位操作。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:edit')")
    @PutMapping("/check")
    public AjaxResult check(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    /**
     * 月报退回 — 上级审核不通过时将月报退回给下级单位（montStat 更新为 "3"）。
     * 退回后下级需根据退回意见修改后重新上报。退回原因写入 montRemark 字段，
     * 下级可在"撤销原因"接口中查看，形成"上报→审核→退回→再上报"的闭环流程。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:edit')")
    @PutMapping("/return")
    public AjaxResult returnMonth(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    /**
     * 月报撤销 — 下级单位在上级审核之前，主动撤销已上报的月报。
     * 撤销后状态回退为"未上报"，允许下级修改数据后重新提交。
     * 该机制避免了下级发现数据错误却无法修改的问题，减少了上下级沟通成本。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:edit')")
    @PutMapping("/revoke")
    public AjaxResult revoke(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    /**
     * 月报加锁/解锁 — 水利部管理员对全国月报进行统一管控。
     * 加锁后，所有下级单位无法上报/修改本月月报；解锁后恢复正常。
     * 该机制用于：①月报截止日期后锁定防止补报；②数据统计期间冻结数据保证一致性。
     * lockStatus 字段 "1" 表示锁定，"0" 表示未锁定。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PreAuthorize("@ss.hasPermi('acci:bisaccimont:edit')")
    @PutMapping("/lock")
    public AjaxResult lock(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    @PutMapping("/batchUnlock")
    public AjaxResult batchUnlock(@RequestParam String[] guids) {
        return toAjax(bisAcciMontService.batchUnlock(guids));
    }

    @PostMapping("/fastReport")
    public AjaxResult fastReport(@RequestParam String guid) {
        ObjAcci acci = objAcciService.selectObjAcciByGuid(guid);
        if (acci == null) return AjaxResult.error("事故不存在");
        BisAcciMont mont = new BisAcciMont();
        mont.setGuid(java.util.UUID.randomUUID().toString().replace("-", ""));
        mont.setAcciCate(acci.getAcciCate());
        mont.setAcciGrad(acci.getAcciGrad());
        mont.setOccuTime(acci.getOccuTime());
        mont.setCasNum(acci.getCasNum());
        mont.setSerInjNum(acci.getSerInjNum());
        mont.setEconLoss(acci.getEconLoss());
        mont.setRepAct("0");
        mont.setAcciWiunType(acci.getAcciWiunType());
        mont.setRepWiunCode(acci.getSgdwName());
        mont.setMont(acci.getOccuTime() != null ? acci.getOccuTime().substring(0, 7) : "");
        mont.setCollTime(java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return toAjax(bisAcciMontService.insertBisAcciMont(mont));
    }

    @PostMapping("/urge")
    public AjaxResult urge(@RequestParam String orgGuid, @RequestParam String repMonth) {
        bisAcciMontService.urgeReport(orgGuid, repMonth);
        return AjaxResult.success();
    }

    /**
     * 月报状态树 — 返回最近3年（去年、今年、明年）的月份层级树结构。
     * 每个月份节点附带 reported 布尔值标记该月是否已上报，前端据此用颜色区分：
     * 绿色（已上报）/ 红色（未上报），让监管单位对每月的上报情况一目了然。
     */
    @GetMapping("/treeData")
    public AjaxResult treeData() {
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(new BisAcciMont());
        List<Map<String, Object>> tree = new java.util.ArrayList<>();
        Calendar cal = Calendar.getInstance();
        int curYear = cal.get(Calendar.YEAR);
        for (int y = curYear; y >= curYear - 2; y--) {
            Map<String, Object> yearNode = new java.util.HashMap<>();
            yearNode.put("id", String.valueOf(y));
            yearNode.put("label", y + "年");
            yearNode.put("pId", "0");
            List<Map<String, Object>> months = new java.util.ArrayList<>();
            for (int m = 12; m >= 1; m--) {
                String ym = y + "-" + String.format("%02d", m);
                Map<String, Object> monthNode = new java.util.HashMap<>();
                monthNode.put("id", ym);
                monthNode.put("label", m + "月");
                monthNode.put("month", String.valueOf(m));
                monthNode.put("pId", String.valueOf(y));
                boolean reported = list.stream().anyMatch(item -> ym.equals(item.getMont()) && ("1".equals(item.getMontStat()) || "2".equals(item.getMontStat())));
                monthNode.put("IsUpload", reported ? 1 : 0);
                months.add(monthNode);
            }
            yearNode.put("children", months);
            tree.add(yearNode);
        }
        return AjaxResult.success(tree);
    }

    /**
     * 月报汇总统计 — 按状态分组统计月报数量，涵盖四种状态：
     * 未上报（无状态）、已上报（1）、已审核（2）、已退回（3）。
     * 用于首页看板展示总体上报进度和审核通过率。
     */
    @GetMapping("/montSummary")
    public AjaxResult montSummary(BisAcciMont query) {
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(query);
        Map<String, int[]> typeStats = new java.util.LinkedHashMap<>();
        typeStats.put("1", new int[]{0, 0});
        typeStats.put("2", new int[]{0, 0});
        typeStats.put("3", new int[]{0, 0});
        for (BisAcciMont m : list) {
            String t = m.getAcciWiunType();
            if (t == null || !typeStats.containsKey(t)) continue;
            int[] s = typeStats.get(t);
            s[0]++;
            if ("1".equals(m.getRepAct()) || "1".equals(m.getMontStat()) || "2".equals(m.getMontStat())) s[1]++;
        }
        List<Map<String, Object>> result = new java.util.ArrayList<>();
        for (Map.Entry<String, int[]> e : typeStats.entrySet()) {
            Map<String, Object> item = new java.util.HashMap<>();
            item.put("repType", e.getKey());
            item.put("totalCount", e.getValue()[0]);
            item.put("repCount", e.getValue()[1]);
            item.put("repAct", e.getValue()[1] > 0 ? "1" : "0");
            result.add(item);
        }
        return AjaxResult.success(result);
    }

    /**
     * 查询加锁状态 — 判断当前月份是否被水利部管理员锁定。
     * 返回 locked 布尔值。锁定状态下，下级单位的前端应禁用"上报/修改"按钮，
     * 并在界面提示"本月数据已锁定，请联系管理员"。
     */
    @GetMapping("/lockStatus")
    public AjaxResult lockStatus(BisAcciMont query) {
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(query);
        Map<String, Object> result = new java.util.HashMap<>();
        result.put("locked", list.stream().anyMatch(m -> "1".equals(m.getLockStatus())));
        return AjaxResult.success(result);
    }

    /**
     * 查询上级上报状态 — 判断上级单位是否已经上报了本月月报。
     * 业务规则：如果上级已上报，则下级不可再上报（防止下级数据覆盖上级汇总结果）。
     * 该接口用于前端在"上报"操作前做前置校验并提示用户。
     */
    @GetMapping("/parentStatus")
    public AjaxResult parentStatus(BisAcciMont query) {
        List<BisAcciMont> list = bisAcciMontService.selectBisAcciMontList(query);
        boolean parentReported = list.stream().anyMatch(m -> "1".equals(m.getMontStat()));
        return AjaxResult.success(Map.of("parentReported", parentReported));
    }

    /**
     * 移动端月报撤销 — 与 PC 端 revoke() 功能相同，但专为移动端提供独立入口。
     * 移动端请求不依赖服务端 Session，参数（用户身份、单位信息）由前端传入，
     * 适用于移动办公场景下现场人员快速撤回错误上报的月报。
     */
    @Log(title = "事故月报管理", businessType = BusinessType.UPDATE)
    @PutMapping("/mobile/cancel")
    public AjaxResult mobileCancel(@RequestBody BisAcciMont bisAcciMont) {
        return toAjax(bisAcciMontService.updateBisAcciMont(bisAcciMont));
    }

    /**
     * 查询撤销原因 — 查看某条月报被上级退回时的审核意见。
     * 退回操作将原因写入 montRemark 字段，下级通过此接口获取退回理由，
     * 据此修正数据后重新上报。是"审核-退回-修改"闭环中的反馈环节。
     */
    @GetMapping("/revokReason/{guid}")
    public AjaxResult revokReason(@PathVariable String guid) {
        BisAcciMont mont = bisAcciMontService.selectBisAcciMontByGuid(guid);
        return AjaxResult.success(mont);
    }
}
