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.PageParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.credit.entity.CreditUser;
import com.gxwebsoft.credit.param.CreditUserImportParam;
import com.gxwebsoft.credit.param.CreditUserParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditCompanyRecordCountService;
import com.gxwebsoft.credit.service.CreditUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
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.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 招投标信息表控制器
 *
 * @author 科技小王子
 * @since 2025-12-15 13:16:04
 */
@Tag(name = "招投标信息表管理")
@RestController
@RequestMapping("/api/credit/credit-user")
public class CreditUserController extends BaseController {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Resource
    private CreditUserService creditUserService;

    @Resource
    private BatchImportSupport batchImportSupport;

    @Resource
    private CreditCompanyService creditCompanyService;

    @Resource
    private CreditCompanyRecordCountService creditCompanyRecordCountService;

    @Operation(summary = "分页查询招投标信息表")
    @GetMapping("/page")
    public ApiResult<PageResult<CreditUser>> page(CreditUserParam param) {
        // 使用关联查询
        return success(creditUserService.pageRel(param));
    }

    @Operation(summary = "查询全部招投标信息表")
    @GetMapping()
    public ApiResult<List<CreditUser>> list(CreditUserParam param) {
        // 使用关联查询
        return success(creditUserService.listRel(param));
    }

    @Operation(summary = "根据id查询招投标信息表")
    @GetMapping("/{id}")
    public ApiResult<CreditUser> get(@PathVariable("id") Integer id) {
        // 使用关联查询
        return success(creditUserService.getByIdRel(id));
    }

    @PreAuthorize("hasAuthority('credit:creditUser:save')")
    @OperationLog
    @Operation(summary = "添加招投标信息表")
    @PostMapping()
    public ApiResult<?> save(@RequestBody CreditUser creditUser) {
        if (creditUserService.save(creditUser)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditUser:update')")
    @OperationLog
    @Operation(summary = "修改招投标信息表")
    @PutMapping()
    public ApiResult<?> update(@RequestBody CreditUser creditUser) {
        if (creditUserService.updateById(creditUser)) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditUser:remove')")
    @OperationLog
    @Operation(summary = "删除招投标信息表")
    @DeleteMapping("/{id}")
    public ApiResult<?> remove(@PathVariable("id") Integer id) {
        if (creditUserService.removeById(id)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('credit:creditUser:save')")
    @OperationLog
    @Operation(summary = "批量添加招投标信息表")
    @PostMapping("/batch")
    public ApiResult<?> saveBatch(@RequestBody List<CreditUser> list) {
        if (creditUserService.saveBatch(list)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditUser:update')")
    @OperationLog
    @Operation(summary = "批量修改招投标信息表")
    @PutMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditUser> batchParam) {
        if (batchParam.update(creditUserService, "id")) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditUser:remove')")
    @OperationLog
    @Operation(summary = "批量删除招投标信息表")
    @DeleteMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
        if (creditUserService.removeByIds(ids)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    /**
     * 根据企业名称匹配企业并更新 companyId（匹配 CreditCompany.name / CreditCompany.matchName）
     *
     * <p>默认仅更新 companyId=0 的记录；如需覆盖更新，传 onlyNull=false。</p>
     */
    @PreAuthorize("hasAuthority('credit:creditUser: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(
            creditUserService,
            creditCompanyService,
            currentTenantId,
            onlyNull,
            limit,
            CreditUser::getId,
            CreditUser::setId,
            CreditUser::getWinningName,
            CreditUser::getCompanyId,
            CreditUser::setCompanyId,
            CreditUser::getHasData,
            CreditUser::setHasData,
            CreditUser::getTenantId,
            CreditUser::new
        );

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

    /**
     * 批量导入招投标信息
     * Excel表头格式：客户名称、唯一标识、类型、企业角色、上级ID、信息类型、所在国家、所在省份、所在城市、所在辖区、街道地址、招采单位名称、中标单位名称、中标金额、备注、是否推荐、到期时间、排序、状态、用户ID、租户ID
     */
    @PreAuthorize("hasAuthority('credit:creditUser: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 {
            int sheetIndex = ExcelImportSupport.findSheetIndex(file, "招投标", 0);
            List<CreditUserImportParam> 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;
            Map<Integer, String> urlMap = readNameHyperlinks(file, sheetIndex, usedTitleRows, usedHeadRows);

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

            for (int i = 0; i < list.size(); i++) {
                CreditUserImportParam param = list.get(i);
                try {
                    CreditUser item = convertImportParamToEntity(param);

                    String link = urlMap.get(i);
                    if (link != null && !link.isEmpty()) {
                        item.setUrl(link);
                    }
                    if (item.getCompanyId() == null && companyId != null) {
                        item.setCompanyId(companyId);
                    }
                    if (item.getCompanyId() != null && item.getCompanyId() > 0) {
                        touchedCompanyIds.add(item.getCompanyId());
                    }

                    // 设置默认值
                    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;
                    }

                    chunkItems.add(item);
                    chunkRowNumbers.add(excelRowNumber);
                    if (chunkItems.size() >= chunkSize) {
                        successCount += batchImportSupport.persistChunkWithFallback(
                            chunkItems,
                            chunkRowNumbers,
                            () -> batchImportSupport.upsertBySingleKey(
                                creditUserService,
                                chunkItems,
                                CreditUser::getId,
                                CreditUser::setId,
                                CreditUser::getName,
                                CreditUser::getName,
                                null,
                                mpBatchSize
                            ),
                            (rowItem, rowNumber) -> {
                                boolean saved = creditUserService.save(rowItem);
                                if (!saved) {
                                    CreditUser existing = creditUserService.getByName(rowItem.getName());
                                    if (existing != null) {
                                        rowItem.setId(existing.getId());
                                        if (creditUserService.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(
                        creditUserService,
                        chunkItems,
                        CreditUser::getId,
                        CreditUser::setId,
                        CreditUser::getName,
                        CreditUser::getName,
                        null,
                        mpBatchSize
                    ),
                    (rowItem, rowNumber) -> {
                        boolean saved = creditUserService.save(rowItem);
                        if (!saved) {
                            CreditUser existing = creditUserService.getByName(rowItem.getName());
                            if (existing != null) {
                                rowItem.setId(existing.getId());
                                if (creditUserService.updateById(rowItem)) {
                                    return true;
                                }
                            }
                        } else {
                            return true;
                        }
                        errorMessages.add("第" + rowNumber + "行：保存失败");
                        return false;
                    },
                    errorMessages
                );
            }

            creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.USER, 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<CreditUserImportParam> templateList = new ArrayList<>();

        CreditUserImportParam example = new CreditUserImportParam();
        example.setCode("CUS001");
        example.setName("示例客户");
        example.setReleaseDate("2023-01-01");
        example.setType(0);
        example.setRole("采购方");
        example.setInfoType("企业");
        example.setAddress("广东省-广州市-南沙区");
        example.setProcurementName("示例招采单位");
        example.setWinningName("示例中标单位");
        example.setWinningPrice("100000");
        templateList.add(example);

        ExportParams exportParams = new ExportParams("招投标信息导入模板", "招投标信息");

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

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

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

    private List<CreditUserImportParam> 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(), CreditUserImportParam.class, importParams);
    }

    /**
     * 读取“项目名称”列的超链接，按数据行顺序返回。
     */
    private Map<Integer, String> readNameHyperlinks(MultipartFile file, int sheetIndex, int titleRows, int headRows) throws Exception {
        Map<Integer, String> result = new HashMap<>();
        try (InputStream is = file.getInputStream(); Workbook workbook = WorkbookFactory.create(is)) {
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            if (sheet == null) {
                return result;
            }
            int headerRowNum = titleRows + headRows - 1;
            Row headerRow = sheet.getRow(headerRowNum);
            int nameColIndex = 0;
            if (headerRow != null) {
                for (int c = headerRow.getFirstCellNum(); c < headerRow.getLastCellNum(); c++) {
                    Cell cell = headerRow.getCell(c);
                    if (cell != null && "项目名称".equals(cell.getStringCellValue())) {
                        nameColIndex = c;
                        break;
                    }
                }
            }
            int dataStartRow = titleRows + headRows;
            for (int r = dataStartRow; r <= sheet.getLastRowNum(); r++) {
                Row row = sheet.getRow(r);
                if (row == null) {
                    continue;
                }
                Cell cell = row.getCell(nameColIndex);
                if (cell != null && cell.getHyperlink() != null) {
                    String address = cell.getHyperlink().getAddress();
                    if (address != null && !address.isEmpty()) {
                        result.put(r - dataStartRow, address);
                    }
                }
            }
        }
        return result;
    }

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

    private boolean isEmptyImportRow(CreditUserImportParam param) {
        if (param == null) {
            return true;
        }
        return isBlank(param.getName())
                && isBlank(param.getCode())
                && isBlank(param.getRole())
                && isBlank(param.getInfoType())
                && isBlank(param.getAddress())
                && isBlank(param.getProcurementName())
                && isBlank(param.getWinningName())
                && isBlank(param.getWinningPrice());
    }

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

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

        entity.setCode(param.getCode());
        entity.setName(param.getName());
        entity.setReleaseDate(param.getReleaseDate());
        entity.setType(param.getType());
        entity.setRole(param.getRole());
        entity.setInfoType(param.getInfoType());
        entity.setAddress(param.getAddress());
        entity.setProcurementName(param.getProcurementName());
        entity.setWinningName(param.getWinningName());
        entity.setWinningPrice(param.getWinningPrice());

        return entity;
    }

}
