package com.jeesharp.business.modules.mall.application;

import com.jeesharp.business.modules.common.enums.ShelfStatusEnum;

import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.mall.convert.MallSpuConvert;
import com.jeesharp.business.modules.mall.dto.MallProductSaveDTO;
import com.jeesharp.business.modules.mall.dto.MallSpuAuditDTO;
import com.jeesharp.business.modules.mall.dto.MallSpuSaveDTO;
import com.jeesharp.business.modules.mall.enums.MallSpuAuditStatusEnum;

import com.jeesharp.business.modules.mall.application.support.MallSettleOnboardingGuard;
import com.jeesharp.business.modules.common.constants.PlatformTenantConstants;
import com.jeesharp.business.modules.mall.entity.MallBrand;
import com.jeesharp.business.modules.mall.entity.MallCategory;
import com.jeesharp.business.modules.mall.entity.MallProductTemplateItem;
import com.jeesharp.business.modules.mall.entity.MallSku;
import com.jeesharp.business.modules.mall.entity.MallSpu;
import com.jeesharp.business.modules.mall.entity.MallSpuExtAttr;
import com.jeesharp.business.modules.mall.enums.MallProductTemplateItemTypeEnum;
import com.jeesharp.business.modules.mall.service.MallBrandService;
import com.jeesharp.business.modules.mall.service.MallCategoryService;
import com.jeesharp.business.modules.mall.service.MallProductTemplateItemService;
import com.jeesharp.business.modules.mall.service.MallSettingService;
import com.jeesharp.business.modules.mall.service.MallSkuService;
import com.jeesharp.business.modules.mall.service.MallSpuExtAttrService;
import com.jeesharp.business.modules.mall.service.MallSpuService;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.utils.WebFrameworkUtils;
import com.jeesharp.business.modules.mall.vo.MallSkuQueryVO;
import com.jeesharp.business.modules.mall.vo.MallSpuExtAttrVO;
import com.jeesharp.business.modules.mall.vo.MallSettleShelfHintVO;
import com.jeesharp.business.modules.mall.vo.MallSpuInfoVO;
import com.jeesharp.business.modules.mall.vo.MallSpuListVO;
import com.jeesharp.business.modules.mall.vo.MallSpuQueryVO;
import com.jeesharp.framework.pojo.Page;
import com.jeesharp.framework.pojo.query.PageRespVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商品SPU Application Service
 * 职责：服务编排，协调各个领域服务
 */
@Slf4j
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MallSpuApplicationService {

    private static final String PRODUCT_AUDIT_ENABLED_KEY = "product_audit_enabled";

    private final MallSpuService mallSpuService;
    private final MallSkuService mallSkuService;
    private final MallSpuExtAttrService mallSpuExtAttrService;
    private final MallCategoryService mallCategoryService;
    private final MallBrandService mallBrandService;
    private final MallProductTemplateItemService mallProductTemplateItemService;
    private final MallSettingService mallSettingService;
    private final MallSettleOnboardingGuard mallSettleOnboardingGuard;

    /**
     * 商品编辑页：查询当前商户结算模式与微信进件状态，用于上架前提示。
     */
    public MallSettleShelfHintVO getSettleShelfHint(String spuId) {
        return mallSettleOnboardingGuard.evaluateShelfHint(resolveMerchantTenantId(spuId));
    }

    /**
     * 获取商品详情
     */
    public MallSpuInfoVO get(String id) {
        log.debug("获取商品详情: {}", id);
        MallSpu entity = mallSpuService.get(id);
        if (entity == null) {
            return null;
        }
        MallSpuInfoVO vo = MallSpuConvert.INSTANCE.toInfoVO(entity);
        List<MallSpuExtAttr> rows = mallSpuExtAttrService.listBySpuId(id);
        List<MallSpuExtAttrVO> ext = new ArrayList<>(rows.size());
        for (MallSpuExtAttr r : rows) {
            MallSpuExtAttrVO x = new MallSpuExtAttrVO();
            x.setAttrKey(r.getAttrKey());
            x.setAttrValue(r.getAttrValue());
            ext.add(x);
        }
        vo.setExtAttrs(ext);
        enrichCategoryAndBrand(vo);
        return vo;
    }

    /**
     * 查询 SPU 下已启用 SKU 的最低销售价（无 SKU 或价格为空时返回 {@code null}）。
     * <p>供 C 端门户等场景展示「起售价」使用。</p>
     *
     * @param spuId 商品 SPU 主键
     * @return 最低 {@link BigDecimal} 售价，可能为 {@code null}
     */
    public BigDecimal getMinSalePrice(String spuId) {
        return mallSkuService.getMinSalePrice(spuId);
    }

    /**
     * 查询 SPU 下已启用的 SKU 列表（用于 C 端规格展示等）。
     */
    public List<MallSku> listEnabledSkus(String spuId) {
        return mallSkuService.listEnabledSkus(spuId);
    }

    /**
     * C 端商品详情「规格参数」表格：品牌、类目、扩展属性（展示名优先取类目继承模板中 {@code attr_name}）。
     *
     * @param spuId SPU 主键
     * @return {@code name}/{@code value} 行列表；商品不存在或无任何项时返回一行占位说明
     */
    public List<Map<String, String>> listPortalProductSpecParams(String spuId) {
        List<Map<String, String>> list = new ArrayList<>();
        MallSpuInfoVO spu = get(spuId);
        if (spu == null) {
            return appendPlaceholderRow(list);
        }
        if (StrUtil.isNotBlank(spu.getBrandName())) {
            Map<String, String> row = new LinkedHashMap<>();
            row.put("name", "品牌");
            row.put("value", spu.getBrandName().trim());
            list.add(row);
        }
        if (StrUtil.isNotBlank(spu.getCategoryName())) {
            Map<String, String> row = new LinkedHashMap<>();
            row.put("name", "分类");
            row.put("value", spu.getCategoryName().trim());
            list.add(row);
        }
        Map<String, String> attrKeyToLabel = buildAttrKeyToDisplayLabel(spu.getCategoryId());
        if (spu.getExtAttrs() != null) {
            for (MallSpuExtAttrVO row : spu.getExtAttrs()) {
                if (row == null || StrUtil.isBlank(row.getAttrKey())) {
                    continue;
                }
                String key = row.getAttrKey().trim();
                Map<String, String> line = new LinkedHashMap<>();
                line.put("name", attrKeyToLabel.getOrDefault(key, key));
                line.put("value", row.getAttrValue() != null ? row.getAttrValue() : "");
                list.add(line);
            }
        }
        if (list.isEmpty()) {
            return appendPlaceholderRow(list);
        }
        return list;
    }

    private static List<Map<String, String>> appendPlaceholderRow(List<Map<String, String>> list) {
        Map<String, String> row = new LinkedHashMap<>();
        row.put("name", "说明");
        row.put("value", "详见商品详情");
        list.add(row);
        return list;
    }

    /**
     * 按类目继承的发布模板，解析扩展属性 {@code attr_key} → 展示名（模板 {@code attr_name}，缺省回退为 key）。
     */
    private Map<String, String> buildAttrKeyToDisplayLabel(String categoryId) {
        if (StrUtil.isBlank(categoryId)) {
            return Collections.emptyMap();
        }
        String templateId = mallCategoryService.resolveInheritedTemplateId(categoryId);
        if (StrUtil.isBlank(templateId)) {
            return Collections.emptyMap();
        }
        List<MallProductTemplateItem> lines = mallProductTemplateItemService.listByTemplateId(templateId);
        Map<String, String> map = new LinkedHashMap<>();
        for (MallProductTemplateItem line : lines) {
            if (line == null || !MallProductTemplateItemTypeEnum.ATTR.getValue().equals(line.getItemType())) {
                continue;
            }
            if (StrUtil.isBlank(line.getAttrKey())) {
                continue;
            }
            String k = line.getAttrKey().trim();
            String label = StrUtil.isNotBlank(line.getAttrName()) ? line.getAttrName().trim() : k;
            map.putIfAbsent(k, label);
        }
        return map;
    }

    /**
     * 管理端按 SPU 查询 SKU 全量列表（含禁用），用于商品编辑页多规格表格回填。
     * <p>条数上限 500，与后台列表分页上限一致。</p>
     *
     * @param spuId 商品 SPU 主键
     * @return 未删除的 SKU 列表，可能为空列表
     */
    public List<MallSku> listSkusBySpuIdForAdmin(String spuId) {
        if (StrUtil.isBlank(spuId)) {
            return List.of();
        }
        MallSkuQueryVO q = new MallSkuQueryVO();
        q.setSpuId(spuId);
        q.setPageNo(1L);
        q.setPageSize(500L);
        return mallSkuService.findList(q);
    }

    /**
     * 分页查询商品（管理端：仅当前登录租户数据）
     */
    public PageRespVO<MallSpuListVO> findPage(Page<MallSpu> page, MallSpuQueryVO query) {
        MallSpuQueryVO prepared = prepareMerchantSpuQuery(query);
        log.debug("分页查询商品: {}", prepared);
        Page<MallSpu> result = mallSpuService.findPage(page, prepared);
        PageRespVO<MallSpuListVO> pageVo = MallSpuConvert.INSTANCE.toPageRespVO(result);
        enrichCategoryAndBrand(pageVo.getRecords());
        return pageVo;
    }

    /**
     * 平台侧待审核/已审商品分页（跨租户）。
     */
    public PageRespVO<MallSpuListVO> findAuditPage(Page<MallSpu> page, MallSpuQueryVO query) {
        assertPlatformOperator();
        if (query.getAuditStatus() == null) {
            query.setAuditStatus(MallSpuAuditStatusEnum.PENDING.getValue());
        }
        Page<MallSpu> result = mallSpuService.findPageForPlatformAudit(page, query);
        PageRespVO<MallSpuListVO> pageVo = MallSpuConvert.INSTANCE.toPageRespVO(result);
        enrichCategoryAndBrand(pageVo.getRecords());
        return pageVo;
    }

    /**
     * 平台审核商品（通过 / 驳回）。
     */
    @Transactional(readOnly = false)
    public void auditSpu(MallSpuAuditDTO dto) {
        assertPlatformOperator();
        if (MallSpuAuditStatusEnum.PASSED.getValue().equals(dto.getAuditStatus())) {
            MallSpu spu = mallSpuService.get(dto.getId());
            if (spu != null) {
                mallSettleOnboardingGuard.assertCanShelf(spu.getTenantId());
            }
        }
        mallSpuService.auditSpu(
            dto.getId(),
            dto.getAuditStatus(),
            WebFrameworkUtils.getLoginUserId(),
            dto.getAuditRemark()
        );
    }

    public boolean isProductAuditEnabled() {
        String value = mallSettingService.getConfigValue(PRODUCT_AUDIT_ENABLED_KEY);
        if (StrUtil.isBlank(value)) {
            return true;
        }
        String trimmed = value.trim();
        return "1".equals(trimmed) || "true".equalsIgnoreCase(trimmed);
    }

    /**
     * C 端门户：已上架且审核已通过的商品列表（条数上限由调用方控制）。
     */
    public List<MallSpuInfoVO> listOnShelfSpusForPortal(int limit) {
        return listOnShelfSpusForPortal(limit, null);
    }

    /**
     * C 端门户：同上；{@code categoryId} 非空时仅返回该分类下商品。
     */
    public List<MallSpuInfoVO> listOnShelfSpusForPortal(int limit, String categoryId) {
        List<MallSpu> spus;
        if (StrUtil.isNotBlank(categoryId)) {
            List<String> categoryIds = mallCategoryService.listSelfAndDescendantIds(categoryId.trim());
            if (categoryIds.isEmpty()) {
                return List.of();
            }
            spus = mallSpuService.listOnShelfSpusForPortalByCategoryIds(limit, categoryIds);
        } else {
            spus = mallSpuService.listOnShelfSpusForPortalByCategoryIds(limit, null);
        }
        return spus.stream()
            .map(MallSpuConvert.INSTANCE::toInfoVO)
            .toList();
    }

    /**
     * C 端门户：按商品名称关键词搜索已上架商品。
     */
    public List<MallSpuInfoVO> searchOnShelfSpusForPortal(int limit, String keyword) {
        if (StrUtil.isBlank(keyword)) {
            return List.of();
        }
        return mallSpuService.searchOnShelfSpusForPortal(limit, keyword.trim()).stream()
            .map(MallSpuConvert.INSTANCE::toInfoVO)
            .toList();
    }

    /**
     * C 端门户：猜你喜欢等推荐位（按虚拟销量降序）。
     */
    public List<MallSpuInfoVO> listRecommendSpusForPortal(int limit) {
        return mallSpuService.listRecommendSpusForPortal(limit).stream()
            .map(MallSpuConvert.INSTANCE::toInfoVO)
            .toList();
    }

    /**
     * 保存简单SPU信息（向后兼容）
     */
    @Transactional
    public void save(MallSpuSaveDTO dto) {
        log.info("保存简单SPU信息: {}", dto.getSpuName());
        boolean auditEnabled = isProductAuditEnabled();
        assertOnboardingIfGoingOnShelf(dto.getStatus(), dto.getId(), auditEnabled);
        if (StrUtil.isBlank(dto.getId())) {
            mallSkuService.createSimpleProduct(dto, auditEnabled);
        } else {
            mallSkuService.updateSimpleProduct(dto, auditEnabled);
        }
        log.info("简单SPU信息保存完成: {}", dto.getSpuName());
    }

    /**
     * 保存完整商品信息
     */
    @Transactional
    public void saveProduct(MallProductSaveDTO dto) {
        log.info("开始编排商品保存流程: {}", dto.getSpuName());
        assertOnboardingIfGoingOnShelf(dto.getStatus(), dto.getSpuId(), isProductAuditEnabled());
        mallSkuService.validateProductData(dto);
        mallSkuService.executeSaveProduct(dto, isProductAuditEnabled());
        log.info("商品保存流程编排完成: {}", dto.getSpuName());
    }

    /**
     * 删除商品
     * ApplicationService只负责编排，不处理具体业务逻辑
     */
    @Transactional
    public void delete(String ids) {
        log.info("开始编排商品删除流程: {}", ids);
        mallSkuService.deleteProducts(ids);
        log.info("商品删除流程编排完成: {}", ids);
    }

    private void enrichCategoryAndBrand(MallSpuInfoVO vo) {
        if (vo == null) {
            return;
        }
        if (StrUtil.isNotBlank(vo.getCategoryId())) {
            MallCategory category = mallCategoryService.get(vo.getCategoryId());
            if (category != null) {
                vo.setCategoryName(category.getCategoryName());
            }
        }
        if (StrUtil.isNotBlank(vo.getBrandId())) {
            MallBrand brand = mallBrandService.get(vo.getBrandId());
            if (brand != null) {
                vo.setBrandName(brand.getBrandName());
            }
        }
    }

    private void assertPlatformOperator() {
        String tenantCode = WebFrameworkUtils.getLoginUserTenantCode();
        if (!PlatformTenantConstants.isPlatformTenantCode(tenantCode)) {
            throw new BizErrorException("仅平台管理员可执行商品审核");
        }
    }

    /**
     * 管理端商品列表：强制按当前登录租户隔离（覆盖前端传入的租户条件，并关闭 dataScope 平台放行）。
     */
    private MallSpuQueryVO prepareMerchantSpuQuery(MallSpuQueryVO query) {
        MallSpuQueryVO q = query != null ? query : new MallSpuQueryVO();
        String tenantCode = WebFrameworkUtils.getLoginUserTenantCode();
        if (StrUtil.isBlank(tenantCode)) {
            throw new BizErrorException("无法识别当前租户，请重新登录");
        }
        q.setTenantCode(tenantCode.trim());
        String tenantId = WebFrameworkUtils.getLoginUserTenantId();
        if (StrUtil.isNotBlank(tenantId)) {
            q.setTenantId(tenantId.trim());
        }
        q.closeDataScope();
        return q;
    }

    /**
     * 未开启审核且请求上架时，校验分账商户是否已完成微信进件。
     */
    private void assertOnboardingIfGoingOnShelf(Integer requestedStatus, String spuId, boolean auditEnabled) {
        if (auditEnabled) {
            return;
        }
        Integer effectiveStatus = requestedStatus;
        if (effectiveStatus == null && StrUtil.isBlank(spuId)) {
            effectiveStatus = ShelfStatusEnum.ONLINE.getValue();
        }
        if (!ShelfStatusEnum.ONLINE.getValue().equals(effectiveStatus)) {
            return;
        }
        mallSettleOnboardingGuard.assertCanShelf(resolveMerchantTenantId(spuId));
    }

    private String resolveMerchantTenantId(String spuId) {
        if (StrUtil.isNotBlank(spuId)) {
            MallSpu spu = mallSpuService.get(spuId);
            if (spu != null && StrUtil.isNotBlank(spu.getTenantId())) {
                return spu.getTenantId();
            }
        }
        String tenantId = WebFrameworkUtils.getLoginUserTenantId();
        if (StrUtil.isBlank(tenantId)) {
            throw new BizErrorException("无法识别商户租户，请重新登录");
        }
        return tenantId;
    }

    private void enrichCategoryAndBrand(List<MallSpuListVO> rows) {
        if (rows == null || rows.isEmpty()) {
            return;
        }
        List<String> categoryIds = rows.stream()
            .map(MallSpuListVO::getCategoryId)
            .filter(StrUtil::isNotBlank)
            .map(String::trim)
            .distinct()
            .collect(Collectors.toList());
        List<String> brandIds = rows.stream()
            .map(MallSpuListVO::getBrandId)
            .filter(StrUtil::isNotBlank)
            .map(String::trim)
            .distinct()
            .collect(Collectors.toList());

        Map<String, String> categoryNameMap = mallCategoryService.listByIds(categoryIds).stream()
            .filter(c -> c != null && StrUtil.isNotBlank(c.getId()))
            .collect(Collectors.toMap(MallCategory::getId, MallCategory::getCategoryName, (a, b) -> a));
        Map<String, String> brandNameMap = mallBrandService.listByIds(brandIds).stream()
            .filter(b -> b != null && StrUtil.isNotBlank(b.getId()))
            .collect(Collectors.toMap(MallBrand::getId, MallBrand::getBrandName, (a, b) -> a));

        for (MallSpuListVO row : rows) {
            if (StrUtil.isNotBlank(row.getCategoryId())) {
                row.setCategoryName(categoryNameMap.get(row.getCategoryId()));
            }
            if (StrUtil.isNotBlank(row.getBrandId())) {
                row.setBrandName(brandNameMap.get(row.getBrandId()));
            }
        }
    }
}
