package com.ruoyi.asset.controller;

import java.util.List;
import com.ruoyi.asset.domain.AmsAsset;
import com.ruoyi.asset.domain.AmsReceiveOrder;
import com.ruoyi.asset.service.IAmsReceiveOrderService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 资产领用管理控制器（Controller）
 * 
 * 负责接收前端关于资产领用流程的 HTTP 请求，并分发至 IAmsReceiveOrderService 进行处理。
 * 权限标识统一以 `asset:receive:` 为前缀，在各操作端点对操作人的登录账号、主键ID及部门信息进行强安全绑定。
 *
 * @author Yangk
 */
@Controller
@RequestMapping("/asset/receive")
public class AmsReceiveOrderController extends BaseController
{
    private String prefix = "asset/receive";

    @Autowired
    private IAmsReceiveOrderService amsReceiveOrderService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserService sysUserService;

    /**
     * 进入领用单列表主页。
     * 业务意图：初始化加载所有正常状态下的部门信息，供搜索条件中的“申请部门”下拉框选择。
     */
    @RequiresPermissions("asset:receive:view")
    @GetMapping()
    public String receive(ModelMap mmap)
    {
        mmap.put("deptList", selectNormalDeptList());
        return prefix + "/receive";
    }

    /**
     * 查询领用单分页列表。
     * 业务意图：支持按单号、申请人、申请部门、确认时间及明细资产编码进行联合分页查询。
     */
    @RequiresPermissions("asset:receive:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(AmsReceiveOrder order)
    {
        startPage();
        return getDataTable(amsReceiveOrderService.selectAmsReceiveOrderList(order));
    }

    /**
     * 弹出资产选择页。
     * 业务意图：在新增或编辑明细添加资产时，弹出模态选择框。传递当前 `orderId`，以便过滤掉已被其他有效单据占用的资产。
     */
    @RequiresPermissions(value = { "asset:receive:add", "asset:receive:edit" }, logical = Logical.OR)
    @GetMapping("/selectAsset")
    public String selectAsset(@RequestParam(value = "orderId", required = false) Long orderId, ModelMap mmap)
    {
        mmap.put("orderId", orderId);
        return prefix + "/selectAsset";
    }

    /**
     * 查询可被当前领用单选择的在库资产列表。
     * 业务意图：过滤获取符合条件的、在库且未被其他领用单占用的资产。供资产选择弹窗分页加载。
     */
    @RequiresPermissions(value = { "asset:receive:add", "asset:receive:edit" }, logical = Logical.OR)
    @PostMapping("/availableAssetList")
    @ResponseBody
    public TableDataInfo availableAssetList(AmsAsset asset,
            @RequestParam(value = "orderId", required = false) Long orderId)
    {
        startPage();
        return getDataTable(amsReceiveOrderService.selectAvailableReceiveAssetList(asset, orderId));
    }

    /**
     * 导出领用单数据为 Excel 文档。
     */
    @RequiresPermissions("asset:receive:export")
    @Log(title = "领用管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(AmsReceiveOrder order)
    {
        List<AmsReceiveOrder> list = amsReceiveOrderService.selectAmsReceiveOrderList(order);
        return new ExcelUtil<AmsReceiveOrder>(AmsReceiveOrder.class).exportExcel(list, "领用管理数据");
    }

    /**
     * 查看领用单详情。
     * 业务意图：展示领用单主表基本信息，并级联展示每一项资产的历史快照及目标归属部门/人。
     */
    @RequiresPermissions("asset:receive:view")
    @GetMapping("/view/{orderId}")
    public String view(@PathVariable("orderId") Long orderId, ModelMap mmap)
    {
        mmap.put("amsReceiveOrder", amsReceiveOrderService.selectAmsReceiveOrderByOrderId(orderId));
        return prefix + "/view";
    }

    /**
     * 跳转至新增领用申请页。
     * 业务意图：为明细列表中的下拉选择初始化提供当前系统所有的正常部门和正常用户列表。
     */
    @RequiresPermissions("asset:receive:add")
    @GetMapping("/add")
    public String add(ModelMap mmap)
    {
        putReceiveOptions(mmap);
        putCurrentApplicant(mmap);
        return prefix + "/add";
    }

    /**
     * 保存新增的资产领用单草稿。
     * 业务意图：将操作人的登录姓名绑定到 createBy，并从当前 Shiro Session 中强绑定操作人用户ID、姓名与部门ID，防止前端伪造申请人。
     */
    @RequiresPermissions("asset:receive:add")
    @Log(title = "领用管理", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(AmsReceiveOrder order)
    {
        order.setCreateBy(getLoginName());
        return toAjax(amsReceiveOrderService.insertAmsReceiveOrder(order, getUserId(),
                getSysUser().getUserName(), getSysUser().getDeptId()));
    }

    /**
     * 跳转至编辑修改页。
     * 业务意图：加载指定ID的领用草稿数据，并初始化填充供选择的部门与人员列表。
     */
    @RequiresPermissions("asset:receive:edit")
    @GetMapping("/edit/{orderId}")
    public String edit(@PathVariable("orderId") Long orderId, ModelMap mmap)
    {
        mmap.put("amsReceiveOrder", amsReceiveOrderService.selectAmsReceiveOrderByOrderId(orderId));
        putReceiveOptions(mmap);
        return prefix + "/edit";
    }

    /**
     * 保存修改后的领用草稿单。
     * 业务意图：将当前操作人登录名绑定到 updateBy，并执行 Service 更新（仅限 DRAFT 状态修改）。
     */
    @RequiresPermissions("asset:receive:edit")
    @Log(title = "领用管理", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(AmsReceiveOrder order)
    {
        order.setUpdateBy(getLoginName());
        return toAjax(amsReceiveOrderService.updateAmsReceiveOrder(order));
    }

    /**
     * 提交资产领用单。
     * 业务意图：将单据状态从 DRAFT 转为 PENDING_CONFIRM (待确认)，并清空历史驳回信息。会强校验资产占用与仓位快照。
     */
    @RequiresPermissions("asset:receive:submit")
    @Log(title = "领用管理", businessType = BusinessType.UPDATE)
    @PostMapping("/submit/{orderId}")
    @ResponseBody
    public AjaxResult submit(@PathVariable("orderId") Long orderId)
    {
        return toAjax(amsReceiveOrderService.submitReceive(orderId, getLoginName()));
    }

    /**
     * 确认领用申请。
     * 业务意图：将单据状态置为 COMPLETED (已完成)。锁定各资产明细、执行状态转移（变为在用、清空仓位并更新使用归属）、生成资产流转履历。
     */
    @RequiresPermissions("asset:receive:confirm")
    @Log(title = "领用管理", businessType = BusinessType.UPDATE)
    @PostMapping("/confirm/{orderId}")
    @ResponseBody
    public AjaxResult confirm(@PathVariable("orderId") Long orderId)
    {
        return toAjax(amsReceiveOrderService.confirmReceive(orderId, getUserId(),
                getSysUser().getUserName(), getLoginName()));
    }

    /**
     * 驳回领用申请。
     * 业务意图：必须填写驳回原因并将状态置为 REJECTED。驳回操作仅流转单据状态，不对资产发生实质修改，可防范资产在审批期间被其他操作变更。
     */
    @RequiresPermissions("asset:receive:reject")
    @Log(title = "领用管理", businessType = BusinessType.UPDATE)
    @PostMapping("/reject/{orderId}")
    @ResponseBody
    public AjaxResult reject(@PathVariable("orderId") Long orderId,
            @RequestParam("rejectReason") String rejectReason)
    {
        return toAjax(amsReceiveOrderService.rejectReceive(orderId, rejectReason, getLoginName()));
    }

    /**
     * 批量逻辑删除领用单草稿。
     * 限制：为了确保历史痕迹，仅 DRAFT 状态单据可以逻辑删除，已提交或确认的单据不允许在此删除。
     */
    @RequiresPermissions("asset:receive:remove")
    @Log(title = "领用管理", businessType = BusinessType.DELETE)
    @PostMapping("/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(amsReceiveOrderService.deleteAmsReceiveOrderByOrderIds(ids));
    }

    /**
     * 构造领用相关的下拉选项列表（正常部门和正常用户），供 Thymeleaf 前端明细项绑定使用。
     */
    private void putReceiveOptions(ModelMap mmap)
    {
        mmap.put("deptList", selectNormalDeptList());
        SysUser user = new SysUser();
        user.setStatus(UserConstants.NORMAL);
        mmap.put("userList", sysUserService.selectUserList(user));
        SysUser currentUser = getSysUser();
        mmap.put("defaultReceiveDeptId", currentUser.getDeptId());
        mmap.put("defaultReceiveUserId", currentUser.getUserId());
    }

    /**
     * 新增领用单时展示当前登录用户的申请人和申请部门快照。
     * 实际保存仍由新增接口从当前会话强制获取，不信任页面提交值。
     */
    private void putCurrentApplicant(ModelMap mmap)
    {
        SysUser currentUser = getSysUser();
        mmap.put("applicantName", currentUser.getUserName());
        SysDept currentDept = sysDeptService.selectDeptById(currentUser.getDeptId());
        mmap.put("applyDeptName", currentDept == null ? "" : currentDept.getDeptName());
    }

    /**
     * 查询系统中全部处于正常（启用且未逻辑删除）状态下的部门列表。
     */
    private List<SysDept> selectNormalDeptList()
    {
        SysDept dept = new SysDept();
        dept.setStatus(UserConstants.DEPT_NORMAL);
        return sysDeptService.selectDeptList(dept);
    }
}
