package com.gxwebsoft.credit.controller;

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.CreditNearbyCompany;
import com.gxwebsoft.credit.param.CreditNearbyCompanyImportParam;
import com.gxwebsoft.credit.param.CreditNearbyCompanyParam;
import com.gxwebsoft.credit.service.CreditCompanyService;
import com.gxwebsoft.credit.service.CreditCompanyRecordCountService;
import com.gxwebsoft.credit.service.CreditNearbyCompanyService;
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 2026-01-07 13:52:14
 */
@Tag(name = "附近企业管理")
@RestController
@RequestMapping("/api/credit/credit-nearby-company")
public class CreditNearbyCompanyController extends BaseController {
    @Resource
    private CreditNearbyCompanyService creditNearbyCompanyService;

    @Resource
    private BatchImportSupport batchImportSupport;

    @Resource
    private CreditCompanyService creditCompanyService;

    @Resource
    private CreditCompanyRecordCountService creditCompanyRecordCountService;

    @Operation(summary = "分页查询附近企业")
    @GetMapping("/page")
    public ApiResult<PageResult<CreditNearbyCompany>> page(CreditNearbyCompanyParam param) {
        // 使用关联查询
        return success(creditNearbyCompanyService.pageRel(param));
    }

    @Operation(summary = "查询全部附近企业")
    @GetMapping()
    public ApiResult<List<CreditNearbyCompany>> list(CreditNearbyCompanyParam param) {
        // 使用关联查询
        return success(creditNearbyCompanyService.listRel(param));
    }

    @Operation(summary = "根据id查询附近企业")
    @GetMapping("/{id}")
    public ApiResult<CreditNearbyCompany> get(@PathVariable("id") Integer id) {
        // 使用关联查询
        return success(creditNearbyCompanyService.getByIdRel(id));
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:save')")
    @OperationLog
    @Operation(summary = "添加附近企业")
    @PostMapping()
    public ApiResult<?> save(@RequestBody CreditNearbyCompany creditNearbyCompany) {
        // 记录当前登录用户id
        // User loginUser = getLoginUser();
        // if (loginUser != null) {
        // creditNearbyCompany.setUserId(loginUser.getUserId());
        // }
        if (creditNearbyCompanyService.save(creditNearbyCompany)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:update')")
    @OperationLog
    @Operation(summary = "修改附近企业")
    @PutMapping()
    public ApiResult<?> update(@RequestBody CreditNearbyCompany creditNearbyCompany) {
        if (creditNearbyCompanyService.updateById(creditNearbyCompany)) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:remove')")
    @OperationLog
    @Operation(summary = "删除附近企业")
    @DeleteMapping("/{id}")
    public ApiResult<?> remove(@PathVariable("id") Integer id) {
        if (creditNearbyCompanyService.removeById(id)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:save')")
    @OperationLog
    @Operation(summary = "批量添加附近企业")
    @PostMapping("/batch")
    public ApiResult<?> saveBatch(@RequestBody List<CreditNearbyCompany> list) {
        if (creditNearbyCompanyService.saveBatch(list)) {
            return success("添加成功");
        }
        return fail("添加失败");
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:update')")
    @OperationLog
    @Operation(summary = "批量修改附近企业")
    @PutMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody BatchParam<CreditNearbyCompany> batchParam) {
        if (batchParam.update(creditNearbyCompanyService, "id")) {
            return success("修改成功");
        }
        return fail("修改失败");
    }

    @PreAuthorize("hasAuthority('credit:creditNearbyCompany:remove')")
    @OperationLog
    @Operation(summary = "批量删除附近企业")
    @DeleteMapping("/batch")
    public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
        if (creditNearbyCompanyService.removeByIds(ids)) {
            return success("删除成功");
        }
        return fail("删除失败");
    }

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

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

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

        try {
            ExcelImportSupport.ImportResult<CreditNearbyCompanyImportParam> importResult = ExcelImportSupport.readAnySheet(
                file, CreditNearbyCompanyImportParam.class, this::isEmptyImportRow);
            List<CreditNearbyCompanyImportParam> list = importResult.getData();
            int usedTitleRows = importResult.getTitleRows();
            int usedHeadRows = importResult.getHeadRows();
            int usedSheetIndex = importResult.getSheetIndex();

            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<String, String> urlByCode = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "统一社会信用代码");
            Map<String, String> urlByName = ExcelImportSupport.readHyperlinksByHeaderKey(file, usedSheetIndex, usedTitleRows, usedHeadRows, "企业名称");

            // 避免逐行写库：按批处理，显著降低 SQL 次数与事务开销
            final int chunkSize = 500;
            final int mpBatchSize = 500;
            List<CreditNearbyCompany> chunkItems = new ArrayList<>(chunkSize);
            List<Integer> chunkRowNumbers = new ArrayList<>(chunkSize);

            for (int i = 0; i < list.size(); i++) {
                CreditNearbyCompanyImportParam param = list.get(i);
                try {
                    CreditNearbyCompany item = convertImportParamToEntity(param);
                    String link = null;
                    if (!ImportHelper.isBlank(item.getCode())) {
                        link = urlByCode.get(item.getCode().trim());
                    }
                    if ((link == null || link.isEmpty()) && !ImportHelper.isBlank(item.getName())) {
                        link = urlByName.get(item.getName().trim());
                    }
                    if (link != null && !link.isEmpty()) {
                        item.setUrl(link);
                    }

                    if (item.getParentId() == null && parentId != null) {
                        item.setParentId(parentId);
                    }
                    if (item.getType() == null && type != null) {
                        item.setType(type);
                    }
                    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.getDeleted() == null) {
                        item.setDeleted(0);
                    }

                    int excelRowNumber = i + 1 + usedTitleRows + usedHeadRows;
                    if (ImportHelper.isBlank(item.getName())) {
                        errorMessages.add("第" + excelRowNumber + "行：企业名称不能为空");
                        continue;
                    }

                    chunkItems.add(item);
                    chunkRowNumbers.add(excelRowNumber);
                    if (chunkItems.size() >= chunkSize) {
                        successCount += persistImportChunk(chunkItems, chunkRowNumbers, companyId, parentId, type, currentTenantId, mpBatchSize, 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 += persistImportChunk(chunkItems, chunkRowNumbers, companyId, parentId, type, currentTenantId, mpBatchSize, errorMessages);
            }

            creditCompanyRecordCountService.refresh(CreditCompanyRecordCountService.CountType.NEARBY_COMPANY, 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);
        }
    }

    private int persistImportChunk(List<CreditNearbyCompany> items,
                                   List<Integer> excelRowNumbers,
                                   Integer companyId,
                                   Integer parentId,
                                   Integer type,
                                   Integer tenantId,
                                   int mpBatchSize,
                                   List<String> errorMessages) {
        return batchImportSupport.persistChunkWithFallback(
            items,
            excelRowNumbers,
            () -> batchImportSupport.upsertByCodeOrName(
                creditNearbyCompanyService,
                items,
                CreditNearbyCompany::getId,
                CreditNearbyCompany::setId,
                CreditNearbyCompany::getCode,
                CreditNearbyCompany::getCode,
                CreditNearbyCompany::getName,
                CreditNearbyCompany::getName,
                wrapper -> {
                    if (companyId != null) {
                        wrapper.eq(CreditNearbyCompany::getCompanyId, companyId);
                    }
                    if (parentId != null) {
                        wrapper.eq(CreditNearbyCompany::getParentId, parentId);
                    }
                    if (type != null) {
                        wrapper.eq(CreditNearbyCompany::getType, type);
                    }
                    if (tenantId != null) {
                        wrapper.eq(CreditNearbyCompany::getTenantId, tenantId);
                    }
                },
                mpBatchSize
            ),
            (item, excelRowNumber) -> {
                boolean saved = creditNearbyCompanyService.save(item);
                if (!saved) {
                    CreditNearbyCompany existing = creditNearbyCompanyService.lambdaQuery()
                        .eq(!ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getCode, item.getCode())
                        .eq(ImportHelper.isBlank(item.getCode()), CreditNearbyCompany::getName, item.getName())
                        .eq(item.getCompanyId() != null, CreditNearbyCompany::getCompanyId, item.getCompanyId())
                        .eq(item.getParentId() != null, CreditNearbyCompany::getParentId, item.getParentId())
                        .eq(item.getType() != null, CreditNearbyCompany::getType, item.getType())
                        .eq(item.getTenantId() != null, CreditNearbyCompany::getTenantId, item.getTenantId())
                        .one();
                    if (existing != null) {
                        item.setId(existing.getId());
                        if (creditNearbyCompanyService.updateById(item)) {
                            return true;
                        }
                    }
                } else {
                    return true;
                }
                String prefix = excelRowNumber > 0 ? ("第" + excelRowNumber + "行：") : "";
                errorMessages.add(prefix + "保存失败");
                return false;
            },
            errorMessages
        );
    }

    /**
     * 下载附近企业导入模板
     */
    @Operation(summary = "下载附近企业导入模板")
    @GetMapping("/import/template")
    public void downloadTemplate(HttpServletResponse response) throws IOException {
        List<CreditNearbyCompanyImportParam> templateList = new ArrayList<>();

        CreditNearbyCompanyImportParam example = new CreditNearbyCompanyImportParam();
        example.setName("示例科技有限公司");
        example.setRegistrationStatus("存续");
        example.setLegalPerson("李四");
        example.setRegisteredCapital("1000万人民币");
        example.setPaidinCapital("200万人民币");
        example.setEstablishDate("2018-06-01");
        example.setCode("91440101MA5XXXXXXX");
        example.setAddress("广西南宁市某某路1号");
        example.setPhone("13800000000");
        example.setEmail("demo@example.com");
        example.setProvince("广西");
        example.setCity("南宁");
        example.setRegion("青秀区");
        example.setDomain("https://example.com");
        example.setInstitutionType("有限责任公司");
        example.setCompanySize("小微企业");
        example.setRegistrationAuthority("南宁市市场监督管理局");
        example.setTaxpayerQualification("一般纳税人");
        example.setLatestAnnualReportYear("2023");
        example.setLatestAnnualReportOnOperatingRevenue("1000万");
        example.setEnterpriseScoreCheck("85");
        example.setCreditRating("A级");
        example.setCechnologyScore("70");
        example.setCechnologyLevel("良好");
        example.setSmallEnterprise("是");
        example.setCompanyProfile("企业简介示例");
        example.setNatureOfBusiness("经营范围示例");
        example.setComments("备注信息");
        templateList.add(example);

        Workbook workbook = ExcelImportSupport.buildTemplate("附近企业导入模板", "附近企业", CreditNearbyCompanyImportParam.class, templateList);

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

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

    private boolean isEmptyImportRow(CreditNearbyCompanyImportParam param) {
        if (param == null) {
            return true;
        }
        if (isImportHeaderRow(param)) {
            return true;
        }
        return ImportHelper.isBlank(param.getName())
            && ImportHelper.isBlank(param.getCode())
            && ImportHelper.isBlank(param.getLegalPerson());
    }

    private boolean isImportHeaderRow(CreditNearbyCompanyImportParam param) {
        return isHeaderValue(param.getName(), "企业名称")
            || isHeaderValue(param.getCode(), "统一社会信用代码")
            || isHeaderValue(param.getLegalPerson(), "法定代表人");
    }

    private static boolean isHeaderValue(String value, String headerText) {
        if (value == null) {
            return false;
        }
        return headerText.equals(value.trim());
    }

    private CreditNearbyCompany convertImportParamToEntity(CreditNearbyCompanyImportParam param) {
        CreditNearbyCompany entity = new CreditNearbyCompany();

        entity.setName(param.getName());
        entity.setRegistrationStatus(param.getRegistrationStatus());
        entity.setLegalPerson(param.getLegalPerson());
        entity.setRegisteredCapital(param.getRegisteredCapital());
        entity.setPaidinCapital(param.getPaidinCapital());
        entity.setEstablishDate(param.getEstablishDate());
        entity.setCode(param.getCode());
        entity.setAddress(param.getAddress());
        entity.setPhone(param.getPhone());
        entity.setEmail(param.getEmail());
        entity.setProvince(param.getProvince());
        entity.setCity(param.getCity());
        entity.setRegion(param.getRegion());
        entity.setDomain(param.getDomain());
        entity.setInstitutionType(param.getInstitutionType());
        entity.setCompanySize(param.getCompanySize());
        entity.setRegistrationAuthority(param.getRegistrationAuthority());
        entity.setTaxpayerQualification(param.getTaxpayerQualification());
        entity.setLatestAnnualReportYear(param.getLatestAnnualReportYear());
        entity.setLatestAnnualReportOnOperatingRevenue(param.getLatestAnnualReportOnOperatingRevenue());
        entity.setEnterpriseScoreCheck(param.getEnterpriseScoreCheck());
        entity.setCreditRating(param.getCreditRating());
        entity.setCechnologyScore(param.getCechnologyScore());
        entity.setCechnologyLevel(param.getCechnologyLevel());
        entity.setSmallEnterprise(param.getSmallEnterprise());
        entity.setCompanyProfile(param.getCompanyProfile());
        entity.setNatureOfBusiness(param.getNatureOfBusiness());
        entity.setComments(param.getComments());

        return entity;
    }

}
