package com.gxwebsoft.credit.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.credit.entity.CreditJudiciary;
import com.gxwebsoft.credit.param.CreditJudiciaryImportParam;
import com.gxwebsoft.credit.param.CreditJudiciaryParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditCompanyRecordCountService;
import com.gxwebsoft.credit.service.CreditJudiciaryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 司法案件控制器
 *
 * @author 科技小王子
 * @since 2025-12-16 15:23:58
 */
@Tag(name = "司法案件管理")
@RestController
@RequestMapping("/api/credit/credit-judiciary")
public class CreditJudiciaryController extends BaseController {
  @Resource
  private CreditJudiciaryService creditJudiciaryService;

  @Resource
  private BatchImportSupport batchImportSupport;

  @Resource
  private CreditCompanyService creditCompanyService;

  @Resource
  private CreditCompanyRecordCountService creditCompanyRecordCountService;

    @Operation(summary = "分页查询司法案件")
    @GetMapping("/page")
    public ApiResult<PageResult<CreditJudiciary>> page(CreditJudiciaryParam param) {
        // 使用关联查询
        return success(creditJudiciaryService.pageRel(param));
    }

    @Operation(summary = "查询全部司法案件")
    @GetMapping()
    public ApiResult<List<CreditJudiciary>> list(CreditJudiciaryParam param) {
        // 使用关联查询
        return success(creditJudiciaryService.listRel(param));
    }

    @Operation(summary = "根据id查询司法案件")
    @GetMapping("/{id}")
    public ApiResult<CreditJudiciary> get(@PathVariable("id") Integer id) {
        // 使用关联查询
        return success(creditJudiciaryService.getByIdRel(id));
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:save')")
    @OperationLog
    @Operation(summary = "添加司法案件")
    @PostMapping()
    public ApiResult<?> save(@RequestBody CreditJudiciary creditJudiciary) {
        if (creditJudiciaryService.save(creditJudiciary)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:update')")
    @OperationLog
    @Operation(summary = "修改司法案件")
    @PutMapping()
    public ApiResult<?> update(@RequestBody CreditJudiciary creditJudiciary) {
        if (creditJudiciaryService.updateById(creditJudiciary)) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:remove')")
    @OperationLog
    @Operation(summary = "删除司法案件")
    @DeleteMapping("/{id}")
    public ApiResult<?> remove(@PathVariable("id") Integer id) {
        if (creditJudiciaryService.removeById(id)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:save')")
    @OperationLog
    @Operation(summary = "批量添加司法案件")
    @PostMapping("/batch")
    public ApiResult<?> saveBatch(@RequestBody List<CreditJudiciary> list) {
        if (creditJudiciaryService.saveBatch(list)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:update')")
    @OperationLog
    @Operation(summary = "批量修改司法案件")
    @PutMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditJudiciary> batchParam) {
        if (batchParam.update(creditJudiciaryService, "id")) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditJudiciary:remove')")
    @OperationLog
    @Operation(summary = "批量删除司法案件")
    @DeleteMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
        if (creditJudiciaryService.removeByIds(ids)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    /**
     * 根据企业名称匹配企业并更新 companyId（匹配 CreditCompany.name / CreditCompany.matchName）
     *
     * <p>默认仅更新 companyId=0 的记录；如需覆盖更新，传 onlyNull=false。</p>
     */
    @PreAuthorize("hasAuthority('credit:creditJudiciary:update')")
    @OperationLog
    @Operation(summary = "根据企业名称匹配并更新companyId")
    @PostMapping("/company-id/refresh")
    public ApiResult<Map<String, Object>> refreshCompanyIdByCompanyName(
        @RequestParam(value = "onlyNull", required = false, defaultValue = "true") Boolean onlyNull,
        @RequestParam(value = "limit", required = false) Integer limit
    ) {
        User loginUser = getLoginUser();
        Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;

        BatchImportSupport.CompanyIdRefreshStats stats = batchImportSupport.refreshCompanyIdByCompanyName(
            creditJudiciaryService,
            creditCompanyService,
            currentTenantId,
            onlyNull,
            limit,
            CreditJudiciary::getId,
            CreditJudiciary::setId,
            CreditJudiciary::getName,
            CreditJudiciary::getCompanyId,
            CreditJudiciary::setCompanyId,
            CreditJudiciary::getHasData,
            CreditJudiciary::setHasData,
            CreditJudiciary::getTenantId,
            CreditJudiciary::new
        );

        if (!stats.anyDataRead) {
            return success("无可更新数据", stats.toMap());
        }
        return success("更新完成，更新" + stats.updated + "条", stats.toMap());
    }

  /**
   * 批量导入司法案件
   */
  @PreAuthorize("hasAuthority('credit:creditJudiciary:save')")
  @Operation(summary = "批量导入司法案件")
  @PostMapping("/import")
  public ApiResult<List<String>> importBatch(@RequestParam("file") MultipartFile file,
                                             @RequestParam(value = "companyId", required = false) Integer companyId) {
    List<String> errorMessages = new ArrayList<>();
    int successCount = 0;
    Set<Integer> touchedCompanyIds = new HashSet<>();

    try {
      // 支持按选项卡名称导入：默认读取“司法案件”sheet（不存在则回退到第 0 个sheet）
      int sheetIndex = ExcelImportSupport.findSheetIndex(file, "司法案件", 0);

      List<CreditJudiciaryImportParam> list = null;
      int usedTitleRows = 0;
      int usedHeadRows = 0;
      int[][] tryConfigs = new int[][]{{1, 1}, {0, 1}, {0, 2}, {0, 3}};

      for (int[] config : tryConfigs) {
        list = filterEmptyRows(tryImport(file, config[0], config[1], sheetIndex));
        if (!CollectionUtils.isEmpty(list)) {
          usedTitleRows = config[0];
          usedHeadRows = config[1];
          break;
        }
      }
      if (CollectionUtils.isEmpty(list)) {
        return fail("未读取到数据，请确认模板表头与示例格式一致", null);
      }

      User loginUser = getLoginUser();
      Integer currentUserId = loginUser != null ? loginUser.getUserId() : null;
      Integer currentTenantId = loginUser != null ? loginUser.getTenantId() : null;
      // easypoi 默认不会读取单元格超链接地址；url 可能挂在“案号/案件名称”等列的超链接中，需要额外读取回填。
      Map<String, String> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, sheetIndex, usedTitleRows, usedHeadRows, "案号");
      Map<String, String> urlByName = ExcelImportSupport.readHyperlinksByHeaderKey(file, sheetIndex, usedTitleRows, usedHeadRows, "案件名称");
      // 有些源文件会单独提供“url/网址/链接”等列（可能是纯文本也可能是超链接）
      Map<String, String> urlByCodeFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(file, sheetIndex, usedTitleRows, usedHeadRows, "案号", "url");
      if (urlByCodeFromUrlCol.isEmpty()) {
        urlByCodeFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(file, sheetIndex, usedTitleRows, usedHeadRows, "案号", "URL");
      }
      if (urlByCodeFromUrlCol.isEmpty()) {
        urlByCodeFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(file, sheetIndex, usedTitleRows, usedHeadRows, "案号", "网址");
      }
      if (urlByCodeFromUrlCol.isEmpty()) {
        urlByCodeFromUrlCol = ExcelImportSupport.readKeyValueByHeaders(file, sheetIndex, usedTitleRows, usedHeadRows, "案号", "链接");
      }

      final int chunkSize = 500;
      final int mpBatchSize = 500;
      List<CreditJudiciary> chunkItems = new ArrayList<>(chunkSize);
      List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);

      for (int i = 0; i < list.size(); i++) {
        CreditJudiciaryImportParam param = list.get(i);
        try {
          CreditJudiciary item = convertImportParamToEntity(param);
          if (!isBlank(item.getCode())) {
            String key = item.getCode().trim();
            String link = urlByCode.get(key);
            if (isBlank(link)) {
              link = urlByCodeFromUrlCol.get(key);
            }
            if (!isBlank(link)) {
              item.setUrl(link.trim());
            }
          } else if (!isBlank(item.getName())) {
            String link = urlByName.get(item.getName().trim());
            if (!isBlank(link)) {
              item.setUrl(link.trim());
            }
          }
          if (item.getCompanyId() == null && companyId != null) {
            item.setCompanyId(companyId);
          }

          // 设置默认值
          if (item.getUserId() == null && currentUserId != null) {
            item.setUserId(currentUserId);
          }
          if (item.getTenantId() == null && currentTenantId != null) {
            item.setTenantId(currentTenantId);
          }
          if (item.getStatus() == null) {
            item.setStatus(0);
          }
          if (item.getRecommend() == null) {
            item.setRecommend(0);
          }
          if (item.getType() == null) {
            item.setType(0);
          }
          if (item.getDeleted() == null) {
            item.setDeleted(0);
          }
          int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
          // 验证必填字段
//          if (item.getName() == null || item.getName().trim().isEmpty()) {
//            errorMessages.add("第" + excelRowNumber + "行：项目名称不能为空");
//            continue;
//          }
          if (item.getCode() == null || item.getCode().trim().isEmpty()) {
            errorMessages.add("第" + excelRowNumber + "行：唯一标识不能为空");
            continue;
          }

          if (item.getCompanyId() != null && item.getCompanyId() > 0) {
            touchedCompanyIds.add(item.getCompanyId());
          }

          chunkItems.add(item);
          chunkRowNumbers.add(excelRowNumber);
          if (chunkItems.size() >= chunkSize) {
            successCount += batchImportSupport.persistChunkWithFallback(
              chunkItems,
              chunkRowNumbers,
              () -> batchImportSupport.upsertBySingleKey(
                creditJudiciaryService,
                chunkItems,
                CreditJudiciary::getId,
                CreditJudiciary::setId,
                CreditJudiciary::getName,
                CreditJudiciary::getName,
                null,
                mpBatchSize
              ),
              (rowItem, rowNumber) -> {
                boolean saved = creditJudiciaryService.save(rowItem);
                if (!saved) {
                  CreditJudiciary existing = creditJudiciaryService.getByName(rowItem.getName());
                  if (existing != null) {
                    rowItem.setId(existing.getId());
                    if (creditJudiciaryService.updateById(rowItem)) {
                      return true;
                    }
                  }
                } else {
                  return true;
                }
                errorMessages.add("第" + rowNumber + "行：保存失败");
                return false;
              },
              errorMessages
            );
            chunkItems.clear();
            chunkRowNumbers.clear();
          }
        } catch (Exception e) {
          int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
          errorMessages.add("第" + excelRowNumber + "行：" + e.getMessage());
          e.printStackTrace();
        }
      }

      if (!chunkItems.isEmpty()) {
        successCount += batchImportSupport.persistChunkWithFallback(
          chunkItems,
          chunkRowNumbers,
          () -> batchImportSupport.upsertBySingleKey(
            creditJudiciaryService,
            chunkItems,
            CreditJudiciary::getId,
            CreditJudiciary::setId,
            CreditJudiciary::getName,
            CreditJudiciary::getName,
            null,
            mpBatchSize
          ),
          (rowItem, rowNumber) -> {
            boolean saved = creditJudiciaryService.save(rowItem);
            if (!saved) {
              CreditJudiciary existing = creditJudiciaryService.getByName(rowItem.getName());
              if (existing != null) {
                rowItem.setId(existing.getId());
                if (creditJudiciaryService.updateById(rowItem)) {
                  return true;
                }
              }
            } else {
              return true;
            }
            errorMessages.add("第" + rowNumber + "行：保存失败");
            return false;
          },
          errorMessages
        );
      }

      creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.JUDICIARY, touchedCompanyIds);

      if (errorMessages.isEmpty()) {
        return success("成功导入" + successCount + "条数据", null);
      } else {
        return success("导入完成，成功" + successCount + "条，失败" + errorMessages.size() + "条", errorMessages);
      }

    } catch (Exception e) {
      e.printStackTrace();
      return fail("导入失败：" + e.getMessage(), null);
    }
  }

    /**
     * 下载司法案件导入模板
     */
    @Operation(summary = "下载司法案件导入模板")
    @GetMapping("/import/template")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
      List<CreditJudiciaryImportParam> templateList = new ArrayList<>();

      CreditJudiciaryImportParam example = new CreditJudiciaryImportParam();
      example.setName("示例客户");
      example.setCode("C0001");
      example.setInfoType("执行案件");
      example.setReason("买卖合同纠纷");
      example.setProcessDate("2025-08-27");
      example.setCaseProgress("首次执行");
      example.setCaseIdentity("被执行人");
      example.setCode("（2025）闽0103执5480号");
      example.setCourt("福建省福州市台江区人民法院");
      example.setCaseAmount("5134060.00");
      templateList.add(example);

      ExportParams exportParams = new ExportParams("司法案件导入模板", "司法案件");

      Workbook workbook = ExcelExportUtil.exportExcel(exportParams, CreditJudiciaryImportParam.class, templateList);

      response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
      response.setHeader("Content-Disposition", "attachment; filename=credit_judiciary_import_template.xlsx");

      workbook.write(response.getOutputStream());
      workbook.close();
    }

    private List<CreditJudiciaryImportParam> tryImport(MultipartFile file, int titleRows, int headRows, int sheetIndex) throws Exception {
      ImportParams importParams = new ImportParams();
      importParams.setTitleRows(titleRows);
      importParams.setHeadRows(headRows);
      importParams.setStartSheetIndex(sheetIndex);
      importParams.setSheetNum(1);
      return ExcelImportUtil.importExcel(file.getInputStream(), CreditJudiciaryImportParam.class, importParams);
    }

    /**
     * 过滤掉完全空白的导入行，避免空行导致导入失败
     */
    private List<CreditJudiciaryImportParam> filterEmptyRows(List<CreditJudiciaryImportParam> rawList) {
      if (CollectionUtils.isEmpty(rawList)) {
        return rawList;
      }
      rawList.removeIf(this::isEmptyImportRow);
      return rawList;
    }

    private boolean isEmptyImportRow(CreditJudiciaryImportParam param) {
      if (param == null) {
        return true;
      }
      return isBlank(param.getName())
        && isBlank(param.getCode())
        && isBlank(param.getName())
        && isBlank(param.getInfoType());
    }

    private boolean isBlank(String value) {
      return value == null || value.trim().isEmpty();
    }

    /**
     * 将CreditJudiciaryImportParam转换为CreditJudiciary实体
     */
    private CreditJudiciary convertImportParamToEntity(CreditJudiciaryImportParam param) {
      CreditJudiciary entity = new CreditJudiciary();

      entity.setCode(param.getCode());
      entity.setName(param.getName());
      entity.setInfoType(param.getInfoType());
      entity.setReason(param.getReason());
      entity.setProcessDate(param.getProcessDate());
      entity.setCaseProgress(param.getCaseProgress());
      entity.setCaseIdentity(param.getCaseIdentity());
      entity.setCourt(param.getCourt());
      entity.setCaseAmount(param.getCaseAmount());

      return entity;
    }

}
