package cn.iocoder.yudao.module.system.controller.admin.biz;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.system.controller.admin.biz.task.TaskStatusManager;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.ElderlyExpenseOrderExportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.OneTimeExpenseImportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.*;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.ExpenseOrderDO;
import cn.iocoder.yudao.module.system.service.biz.ExpenseOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.validation.annotation.Validated;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;


@Tag(name = "管理后台 - 长者账单")
@RestController
@RequestMapping("/elderly/expenseOrder")
@Validated
public class ExpenseOrderController {

    @Resource
    private ExpenseOrderService expenseOrderService;

    @Resource
    private TaskStatusManager taskStatusManager;

    //    @PostMapping("/create")
//    @Operation(summary = "创建长者账单")
//    @PreAuthorize("@ss.hasPermission('elderly:expense-bill:create')")
//    public CommonResult<Long> createExpenseBill(@Valid @RequestBody ExpenseBillSaveReqVO createReqVO) {
//        return success(expenseBillService.createExpenseBill(createReqVO));
//    }
//

    //
//    @DeleteMapping("/delete")
//    @Operation(summary = "删除长者账单")
//    @Parameter(name = "id", description = "编号", required = true)
//    @PreAuthorize("@ss.hasPermission('elderly:expense-bill:delete')")
//    public CommonResult<Boolean> deleteExpenseBill(@RequestParam("id") Long id) {
//        expenseBillService.deleteExpenseBill(id);
//        return success(true);
//    }
//
    @GetMapping("/get")
    @Operation(summary = "获得长者账单详情")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @TenantIgnore
    public CommonResult<ExpenseBillRespVO> getExpenseBill(@RequestParam("id") Long id) {
        ExpenseBillRespVO expenseBill = expenseOrderService.getExpenseBill(id);
        return success(expenseBill);
    }

    @GetMapping("/wx/getOrder")
    @Operation(summary = "获得长者账单详情-供小程序端调用")
    @Parameter(name = "orderId", description = "订单编号", required = true, example = "1024")
    @PermitAll
    public CommonResult<ExpenseBillRespVO> getExpenseOrderByWx(@RequestParam("orderId") Long orderId) {
        ExpenseBillRespVO expenseBill = expenseOrderService.getExpenseBill(orderId);
        expenseBill.setActualAmount(expenseBill.getActualAmount().setScale(2, RoundingMode.DOWN));
        return success(expenseBill);
    }


    @GetMapping("/page")
    @Operation(summary = "获得长者账单分页")
    @TenantIgnore
    public CommonResult<PageResult<ExpenseOrderDO>> getExpenseBillPage(@Valid ExpenseBillPageReqVO pageReqVO) {
        pageReqVO.setTenantIds(Objects.isNull(pageReqVO.getTenantIds()) ? new Long[]{TenantContextHolder.getTenantId()} : pageReqVO.getTenantIds());
        PageResult<ExpenseOrderDO> pageResult = expenseOrderService.getExpenseBillPage(pageReqVO);
        return success(pageResult);
    }


    @GetMapping("/arrearsNote")
    @Operation(summary = "欠费备注")
    @TenantIgnore
    public CommonResult<Boolean> arrearsNote(@RequestParam("id") Long id, @RequestParam("arrearsNote") String arrearsNote) {
        expenseOrderService.arrearsNote(id, arrearsNote);
        return success(true);
    }


    @PostMapping("pay")
    public CommonResult<Boolean> pay(@RequestBody ExpensePayOrderSaveReqVO saveReqVO) {
        expenseOrderService.payOrder(saveReqVO);
        return success(true);
    }

    @PostMapping("/importBatchPay")
    @Operation(summary = "导入批量缴费")
    public void importBatchPay(@RequestBody MultipartFile file, Long tenantId, HttpServletResponse response) throws Exception {
        List<ExpenseOrderBatchPayExcelVO> list = ExcelUtils.read(file, ExpenseOrderBatchPayExcelVO.class);
        List<ExpenseOrderBatchPayExcelVO> payload = expenseOrderService.importBatchPay(list, tenantId);
        ExcelUtils.write(response, "导入批量缴费数据", "导入情况数据", ExpenseOrderBatchPayExcelVO.class, payload);

    }

    @PostMapping("/importBatchAddDeposit")
    @Operation(summary = "导入批量修复押金数据")
    public void importBatchAddDeposit(@RequestBody @RequestParam("file") MultipartFile file, @RequestParam("tenantId") Long tenantId, HttpServletResponse response) throws Exception {
        List<ExpenseOrderBatchPayExcelVO> list = ExcelUtils.read(file, ExpenseOrderBatchPayExcelVO.class);
        List<ExpenseOrderBatchPayExcelVO> payload = expenseOrderService.importBatchAddDeposit(list, tenantId);
        ExcelUtils.write(response, "导入批量修复押金数据", "导入情况数据", ExpenseOrderBatchPayExcelVO.class, payload);

    }


    @GetMapping("/exportExpenseOrderItemExcel")
    @Operation(summary = "导出账单明细Excel")
    public void exportExpenseOrderItemExcel(@RequestParam("expenseOrderId") Long expenseOrderId,
                                            HttpServletResponse response) throws IOException {
        List<ExpenseOrderItemRespVO> list = expenseOrderService.exportExpenseOrderItemExcel(expenseOrderId);
        // 导出 Excel
        ExcelUtils.write(response, "长者账单明细.xls", "账单明细数据", ExpenseOrderItemRespVO.class, list);
    }

    @GetMapping("/queryExpenseBillItem")
    @Operation(summary = "账单生成-根据账单月以及长者Id查询费用项")
    @TenantIgnore
    public CommonResult<List<ExpenseItemRespVO>> queryExpenseBillItem(@RequestParam("billingMonth") String billingMonth, @RequestParam("elderId") Long elderId) {
        return success(expenseOrderService.queryExpenseBillItem(billingMonth, elderId));
    }


    @PostMapping("/generateExpenseBill")
    @Operation(summary = "账单生成")
    @TenantIgnore
    public CommonResult<Boolean> generateExpenseBill(@RequestBody ExpenseOrderSaveVO saveVO) {
        expenseOrderService.generateExpenseBill(saveVO);
        return success(true);
    }


    @GetMapping("/exportExpenseOrderExcel")
    @Operation(summary = "导出账单Excel")
    @TenantIgnore
    public void exportExpenseOrderExcel(ExpenseBillPageReqVO pageReqVO,
                                        HttpServletResponse response) throws IOException {
        expenseOrderService.exportExpenseOrderExcel(response, pageReqVO);

    }

    @GetMapping("/getExpenseOrderPageByElderId")
    @Operation(summary = "根据长者ID查询账单")
    public CommonResult<PageResult<ExpenseOrderDO>> getExpenseOrderPageByElderId(@Valid ExpenseBillPageReqVO pageReqVO) {
        return success(expenseOrderService.getExpenseOrderPageByElderId(pageReqVO));
    }

    @GetMapping("/getExpenseOrderAmountByElderId")
    @Operation(summary = "根据长者ID查询账单缴费总额和欠费总额")
    public CommonResult<Map<String, Object>> getExpenseOrderAmountByElderId(@RequestParam("elderId") Long elderId) {
        return success(expenseOrderService.getExpenseOrderAmountByElderId(elderId));
    }

    @GetMapping("/exportElderlyExpenseOrder")
    @Operation(summary = "导出长者账单Excel")
    @TenantIgnore
    public void exportElderlyExpenseOrder(ExpenseBillPageReqVO pageReqVO,
                                          HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        pageReqVO.setTenantId(Objects.isNull(pageReqVO.getTenantId()) ? TenantContextHolder.getTenantId() : pageReqVO.getTenantId());
        List<ElderlyExpenseOrderExportExcelVO> list = expenseOrderService.exportElderlyExpenseOrder(pageReqVO);
        ElderlyExpenseOrderExportExcelVO excelVO = list.stream().findFirst().get();
        // 导出 Excel
        ExcelUtils.write(response, excelVO.getElderName() + "账单.xls", "账单数据", ElderlyExpenseOrderExportExcelVO.class, list);
    }


    @PostMapping("/batchGenerateExpenseBill")
    @Operation(summary = "批量账单生成")
    @TenantIgnore
    public CommonResult<Map<String, Object>> batchGenerateExpenseBill(@RequestBody ExpenseOrderSaveVO saveVO) {
        try {
            // 初始化任务
            String taskId = taskStatusManager.initTask(saveVO);

            // 异步执行任务
            CompletableFuture.runAsync(() -> {
                TenantUtils.executeIgnore(() -> {
                    try {
                        expenseOrderService.batchGenerateExpenseBill(saveVO, taskId);
                        taskStatusManager.completeTask(taskId);
                    } catch (Exception e) {
                        taskStatusManager.failTask(taskId, e.getMessage());
                    } finally {
                        TenantContextHolder.clear();
                    }
                });
            });

            // 立即返回任务ID
            Map<String, Object> result = new HashMap<>();
            result.put("taskId", taskId);
            result.put("status", "PROCESSING");
            result.put("message", "批量账单生成任务已开始执行");
            return CommonResult.success(result);
        } catch (Exception e) {
            return CommonResult.error(500, "任务启动失败: " + e.getMessage());
        }
    }

    @GetMapping("/batchGenerateExpenseBill/status/{taskId}")
    @Operation(summary = "查询批量生成账单任务状态")
    @TenantIgnore
    public CommonResult<TaskStatusManager.TaskStatus> getBatchTaskStatus(@PathVariable String taskId) {
        TaskStatusManager.TaskStatus status = taskStatusManager.getTaskStatus(taskId);
        if (status == null) {
            return CommonResult.error(404, "任务不存在或已过期");
        }
        return CommonResult.success(status);
    }

    @PostMapping("/importOneTimeExpenseToOrder")
    @Operation(summary = "导入一次性费用（合并账单）")
    @TenantIgnore
    public CommonResult<Map<String, Object>> importOneTimeExpenseToOrder(@RequestBody MultipartFile file) throws IOException {
        List<OneTimeExpenseImportExcelVO> list = ExcelUtils.read(file, OneTimeExpenseImportExcelVO.class);
        return success(expenseOrderService.importOneTimeExpenseToOrder(list));
    }

    @PostMapping("/downFileErrorExcel")
    @Operation(summary = "导出失败的一次性费用excel")
    public void downFileErrorExcel(@RequestBody List<OneTimeExpenseImportExcelVO> payload, HttpServletResponse response) throws IOException {
        ExcelUtils.write(response, "一次性费用", "失败数据", OneTimeExpenseImportExcelVO.class, payload);
    }


    @GetMapping("/cancelPayment")
    @Operation(summary = "撤销订单")
    @TenantIgnore
    public CommonResult<Boolean> cancelPayment(@RequestParam("orderId") Long orderId) {
        expenseOrderService.cancelPayment(orderId);
        return success(true);
    }

    @PostMapping("/editExpenseOrder")
    @Operation(summary = "编辑订单")
    @TenantIgnore
    public CommonResult<Boolean> editExpenseOrder(@RequestBody @Valid ExpenseOrderEditSaveVO saveVO) {
        expenseOrderService.editExpenseOrder(saveVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除未缴费的账单")
    @Parameter(name = "id", description = "账单编号", required = true)
    @TenantIgnore
    public CommonResult<Boolean> deleteExpenseOrder(@RequestParam("id") Long id) {
        expenseOrderService.deleteExpenseOrder(id);
        return success(true);
    }

    @PostMapping("/markCheckinBillsPaid")
    @Operation(summary = "将指定时间之前的入院账单标记为已缴费")
    @TenantIgnore
    public CommonResult<Boolean> markCheckinBillsPaid(@Valid @RequestBody MarkCheckinBillsPaidReqVO reqVO) {
        expenseOrderService.markCheckinBillsPaid(reqVO);
        return success(true);
    }

    @PostMapping("/markSupportElderlyBillsPaid")
    @Operation(summary = "按账单月和机构批量将供养长者账单标记为已缴费")
    @TenantIgnore
    public CommonResult<Boolean> markSupportElderlyBillsPaid(@Valid @RequestBody MarkSupportElderlyBillsPaidReqVO reqVO) {
        expenseOrderService.markSupportElderlyBillsPaid(reqVO);
        return success(true);
    }

    @PutMapping("/confirmStatus")
    @Operation(summary = "账单状态确认")
    @Parameter(name = "orderId", description = "账单编号", required = true)
    @TenantIgnore
    public CommonResult<Boolean> confirmStatus(@RequestParam("orderId") Long orderId) {
        expenseOrderService.updateConfirmStatus(orderId, true);
        return success(true);
    }

    @PostMapping("/sendSmsBillOrder")
    @Operation(summary = "发送账单通知短信")
    @Parameter(name = "orderIds", description = "账单ID数组", required = true)
    @TenantIgnore
    public CommonResult<Boolean> sendSmsBillOrder(@RequestBody List<Long> orderIds) {
        expenseOrderService.sendSmsBillOrder(orderIds);
        return success(true);
    }


    @PostMapping("/pushOrder")
    @Operation(summary = "推送账单到公众号")
    @Parameter(name = "orderIds", description = "账单ID数组", required = true)
    @TenantIgnore
    public CommonResult<String> pushOrder(@RequestBody List<Long> orderIds) {
        return success(expenseOrderService.pushOrder(orderIds));
    }

    @GetMapping("/checkContractNearlyExpire")
    @Operation(summary = "检查合同是否准备到期")
    public CommonResult<Boolean> checkContractNearlyExpire(@RequestParam("elderId") Long elderId,
                                                           @RequestParam("billingMonth") String billingMonth) {
        return success(expenseOrderService.checkContractNearlyExpire(elderId,billingMonth));
    }


    @GetMapping("/getOrderListByUserPhone")
    @Operation(summary = "小程序亲属账单列表")
    @PermitAll
    @TenantIgnore
    public CommonResult<List<ExpenseOrderDO>> getBillOrderList(ExpenseBillPageReqVO pageReqVO) {
        return success(expenseOrderService.getBillOrderList(pageReqVO));
    }
}
