package com.ruoyi.ems.controller;

import com.huashe.common.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.utils.SecurityUtils;

import com.ruoyi.ems.domain.InspectionPlan;
import com.ruoyi.ems.domain.InspectionReport;
import com.ruoyi.ems.domain.ManualReportSubmit;
import com.ruoyi.ems.service.IInspectionPlanService;

import com.ruoyi.ems.task.InspectionScheduler;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * 巡检计划Controller
 *
 * 【重要改动】
 * 在增删改操作后同步调度器状态
 * 调度器仅在 EMS 主模块加载，Service 层保持纯净
 */
@RestController
@RequestMapping("/inspection/plan")
@Api(value = "InspectionPlanController", description = "巡检计划管理")
public class InspectionPlanController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(InspectionPlanController.class);

    /** 计划类型：自动巡检 */
    private static final int PLAN_TYPE_AUTO = 2;

    @Autowired
    private IInspectionPlanService planService;

    /**
     * 注入调度器（仅在EMS主模块存在）
     */
    @Autowired
    private InspectionScheduler inspectionScheduler;

    /**
     * 查询巡检计划列表
     */
    @RequiresPermissions("ems:inspection:plan:list")
    @GetMapping("/list")
    @ApiOperation("查询巡检计划列表")
    public TableDataInfo list(InspectionPlan plan) {
        startPage();
        List<InspectionPlan> list = planService.selectList(plan);
        return getDataTable(list);
    }

    /**
     * 导出巡检计划列表
     */
    @RequiresPermissions("ems:inspection:plan:export")
    @Log(title = "巡检计划", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ApiOperation("导出巡检计划")
    public void export(HttpServletResponse response, InspectionPlan plan) {
        List<InspectionPlan> list = planService.selectList(plan);
        ExcelUtil<InspectionPlan> util = new ExcelUtil<>(InspectionPlan.class);
        util.exportExcel(response, list, "巡检计划数据");
    }

    /**
     * 获取巡检计划详细信息
     */
    @RequiresPermissions("ems:inspection:plan:query")
    @GetMapping("/{id}")
    @ApiOperation("获取巡检计划详情")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        return success(planService.selectById(id));
    }

    /**
     * 根据计划代码获取详情
     */
    @RequiresPermissions("ems:inspection:plan:query")
    @GetMapping("/code/{planCode}")
    @ApiOperation("根据计划代码获取详情")
    public AjaxResult getByCode(@PathVariable("planCode") String planCode) {
        return success(planService.selectByPlanCode(planCode));
    }

    /**
     * 新增巡检计划
     *
     * 【改动】新增后同步注册到调度器
     */
    @RequiresPermissions("ems:inspection:plan:add")
    @Log(title = "巡检计划", businessType = BusinessType.INSERT)
    @PostMapping
    @ApiOperation("新增巡检计划")
    public AjaxResult add(@RequestBody InspectionPlan plan) {
        plan.setCreateBy(SecurityUtils.getUsername());
        int result = planService.insert(plan);

        // 如果是自动巡检且配置了cron，注册到调度器
        if (result > 0 && isSchedulablePlan(plan)) {
            syncSchedulerRegister(plan);
        }

        return toAjax(result);
    }

    /**
     * 修改巡检计划
     *
     * 【改动】修改后刷新调度器配置
     */
    @RequiresPermissions("ems:inspection:plan:edit")
    @Log(title = "巡检计划", businessType = BusinessType.UPDATE)
    @PutMapping
    @ApiOperation("修改巡检计划")
    public AjaxResult edit(@RequestBody InspectionPlan plan) {
        plan.setUpdateBy(SecurityUtils.getUsername());
        int result = planService.update(plan);

        // 刷新调度器配置
        if (result > 0) {
            syncSchedulerRefresh(plan.getPlanCode());
        }

        return toAjax(result);
    }

    /**
     * 删除巡检计划
     *
     * 【改动】删除前从调度器注销
     */
    @RequiresPermissions("ems:inspection:plan:remove")
    @Log(title = "巡检计划", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    @ApiOperation("删除巡检计划")
    public AjaxResult remove(@PathVariable Long[] ids) {
        // 先从调度器注销
        for (Long id : ids) {
            InspectionPlan plan = planService.selectById(id);
            if (plan != null) {
                syncSchedulerUnregister(plan.getPlanCode());
            }
        }

        return toAjax(planService.deleteByIds(ids));
    }

    /**
     * 执行自动巡检
     * 仅用于自动巡检计划（planType=2）
     */
    @RequiresPermissions("ems:inspection:plan:execute")
    @Log(title = "执行自动巡检", businessType = BusinessType.OTHER)
    @PostMapping("/execute/{planCode}")
    @ApiOperation("执行自动巡检")
    public AjaxResult execute(@PathVariable("planCode") String planCode) {
        try {
            String executor = SecurityUtils.getUsername();
            InspectionReport report = planService.executeAutoInspection(planCode, executor);
            return success(report);
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    /**
     * 提交手动巡检报告
     * 用于手动巡检计划（planType=1），工作人员现场巡检后提交报告
     */
    @RequiresPermissions("ems:inspection:plan:execute")
    @Log(title = "提交手动巡检报告", businessType = BusinessType.INSERT)
    @PostMapping("/submitManual")
    @ApiOperation("提交手动巡检报告")
    public AjaxResult submitManualReport(@RequestBody ManualReportSubmit submit) {
        try {
            String submitter = SecurityUtils.getUsername();
            submit.setSubmitter(submitter);
            InspectionReport report = planService.submitManualReport(submit);
            return success(report);
        } catch (Exception e) {
            return error(e.getMessage());
        }
    }

    // ==================== 调度器同步方法 ====================

    /**
     * 判断计划是否可调度
     */
    private boolean isSchedulablePlan(InspectionPlan plan) {
        return plan != null
            && plan.getPlanType() != null
            && plan.getPlanType() == PLAN_TYPE_AUTO
            && StringUtils.isNotBlank(plan.getCronExpression());
    }

    /**
     * 同步注册到调度器
     */
    private void syncSchedulerRegister(InspectionPlan plan) {
        try {
            inspectionScheduler.registerPlan(plan);
            log.info("巡检计划[{}]已注册到调度器", plan.getPlanCode());
        } catch (Exception e) {
            // 注册失败不影响业务，仅记录日志
            log.warn("同步注册调度器失败: planCode={}, error={}", plan.getPlanCode(), e.getMessage());
        }
    }

    /**
     * 同步刷新调度器
     */
    private void syncSchedulerRefresh(String planCode) {
        try {
            inspectionScheduler.refreshPlan(planCode);
            log.info("巡检计划[{}]调度配置已刷新", planCode);
        } catch (Exception e) {
            log.warn("同步刷新调度器失败: planCode={}, error={}", planCode, e.getMessage());
        }
    }

    /**
     * 同步注销调度器
     */
    private void syncSchedulerUnregister(String planCode) {
        try {
            inspectionScheduler.unregisterPlan(planCode);
            log.info("巡检计划[{}]已从调度器注销", planCode);
        } catch (Exception e) {
            log.warn("同步注销调度器失败: planCode={}, error={}", planCode, e.getMessage());
        }
    }
}