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

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

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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.mall.convert.MallCartItemConvert;
import com.jeesharp.business.modules.mall.dto.MallCartItemSaveDTO;
import com.jeesharp.business.modules.mall.entity.MallCartItem;
import com.jeesharp.business.modules.mall.entity.MallSku;
import com.jeesharp.business.modules.mall.entity.MallSpu;
import com.jeesharp.business.modules.mall.enums.MallCartItemSelectedEnum;

import com.jeesharp.business.modules.mall.service.MallCartItemService;
import com.jeesharp.business.modules.mall.service.MallSkuService;
import com.jeesharp.business.modules.mall.service.MallSpuService;
import com.jeesharp.business.modules.mall.vo.MallCartItemInfoVO;
import com.jeesharp.business.modules.mall.vo.MallCartItemListVO;
import com.jeesharp.business.modules.mall.vo.MallCartItemPortalRowVO;
import com.jeesharp.business.modules.mall.vo.MallCartItemQueryVO;
import com.jeesharp.business.modules.member.service.MemberService;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.pojo.Page;
import com.jeesharp.framework.pojo.query.PageRespVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 购物车行应用服务。
 *
 * @author jeesharp
 * @since 2026-05-07
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MallCartItemApplicationService {

    private final MallCartItemService mallCartItemService;
    private final MallSkuService mallSkuService;
    private final MallSpuService mallSpuService;
    private final MemberService memberService;

    public MallCartItemInfoVO get(String id) {
        return MallCartItemConvert.INSTANCE.toInfoVO(mallCartItemService.get(id));
    }

    public PageRespVO<MallCartItemListVO> findPage(Page<MallCartItem> page, MallCartItemQueryVO query) {
        MallCartItemQueryVO prepared = prepareQuery(query);
        if (prepared == null) {
            return emptyPage(page);
        }
        Page<MallCartItem> result = mallCartItemService.findPage(page, prepared);
        PageRespVO<MallCartItemListVO> pageVo = MallCartItemConvert.INSTANCE.toPageRespVO(result);
        enrichListDisplay(pageVo.getRecords());
        return pageVo;
    }

    @Transactional(readOnly = false)
    public void save(MallCartItemSaveDTO dto) {
        MallCartItem entity = MallCartItemConvert.INSTANCE.toEntity(dto);
        if (StrUtil.isBlank(dto.getId()) && entity.getSelected() == null) {
            entity.setSelected(MallCartItemSelectedEnum.SELECTED.getValue());
        }
        if (StrUtil.isBlank(dto.getId())) {
            mallCartItemService.createCartItem(entity);
            return;
        }
        mallCartItemService.updateCartItem(entity);
    }

    @Transactional(readOnly = false)
    public void delete(String ids) {
        mallCartItemService.batchDelete(StrUtil.splitTrim(ids, ','));
    }

    /**
     * C 端购物车：按店铺分组，结构与小程序端 {@code CartMerchant[]} 对齐。
     *
     * @param memberId 当前会员
     * @return merchants 数组，每项含 {@code merchantId}、{@code merchantName}、{@code products}
     */
    public List<Map<String, Object>> listMobileCartGrouped(String memberId) {
        List<MallCartItemPortalRowVO> rows = mallCartItemService.listPortalRowsByMemberId(memberId);
        LinkedHashMap<String, Map<String, Object>> byMerchant = new LinkedHashMap<>();
        for (MallCartItemPortalRowVO r : rows) {
            String mid = StrUtil.blankToDefault(r.getMerchantId(), "");
            Map<String, Object> merchant = byMerchant.computeIfAbsent(mid, k -> {
                Map<String, Object> m = new LinkedHashMap<>();
                m.put("merchantId", mid);
                m.put("merchantName", "官方店铺");
                m.put("products", new ArrayList<Map<String, Object>>());
                return m;
            });
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> products = (List<Map<String, Object>>) merchant.get("products");
            products.add(toMobileProductRow(r));
        }
        return new ArrayList<>(byMerchant.values());
    }

    /**
     * C 端加入购物车：同一会员同一 SKU 合并数量。
     */
    @Transactional(readOnly = false)
    public void addOrMergeForMobile(String memberId, String spuId, String skuId, int quantity) {
        if (quantity <= 0) {
            throw new BizErrorException("数量须大于0");
        }
        MallSku sku = resolveSkuForCart(spuId, skuId);
        MallCartItem existing = mallCartItemService.findActiveByMemberAndSku(memberId, sku.getId());
        if (existing != null) {
            int next = (existing.getQuantity() == null ? 0 : existing.getQuantity()) + quantity;
            existing.setQuantity(next);
            if (existing.getSelected() == null) {
                existing.setSelected(MallCartItemSelectedEnum.SELECTED.getValue());
            }
            mallCartItemService.updateCartItem(existing);
            return;
        }
        MallCartItem row = new MallCartItem();
        row.setMemberId(memberId);
        row.setSpuId(spuId);
        row.setSkuId(sku.getId());
        row.setQuantity(quantity);
        row.setSelected(MallCartItemSelectedEnum.SELECTED.getValue());
        mallCartItemService.createCartItem(row);
    }

    @Transactional(readOnly = false)
    public void updateQuantityForMobile(String memberId, String cartItemId, int quantity) {
        if (quantity < 1) {
            throw new BizErrorException("数量须至少为1");
        }
        MallCartItem row = requireOwnCartItem(memberId, cartItemId);
        row.setQuantity(quantity);
        mallCartItemService.updateCartItem(row);
    }

    @Transactional(readOnly = false)
    public void updateSelectedForMobile(String memberId, String cartItemId, boolean selected) {
        MallCartItem row = requireOwnCartItem(memberId, cartItemId);
        row.setSelected(selected ? MallCartItemSelectedEnum.SELECTED.getValue() : MallCartItemSelectedEnum.UNSELECTED.getValue());
        mallCartItemService.updateCartItem(row);
    }

    @Transactional(readOnly = false)
    public void updateSelectAllForMobile(String memberId, boolean selected) {
        mallCartItemService.updateSelectAllByMember(
            memberId,
            selected ? MallCartItemSelectedEnum.SELECTED.getValue() : MallCartItemSelectedEnum.UNSELECTED.getValue());
    }

    @Transactional(readOnly = false)
    public void removeForMobile(String memberId, List<String> itemIds) {
        mallCartItemService.deleteByMemberAndItemIds(memberId, itemIds);
    }

    private MallCartItem requireOwnCartItem(String memberId, String cartItemId) {
        MallCartItem row = mallCartItemService.get(cartItemId);
        if (row == null || !memberId.equals(row.getMemberId()) || !StrUtil.equals("0", StrUtil.nullToDefault(row.getDelFlag(), ""))) {
            throw new BizErrorException("购物车记录不存在");
        }
        return row;
    }

    private MallSku resolveSkuForCart(String spuId, String skuId) {
        if (StrUtil.isBlank(spuId)) {
            throw new BizErrorException("商品SPU不能为空");
        }
        MallSpu spu = mallSpuService.get(spuId);
        if (spu == null || !ShelfStatusEnum.ONLINE.getValue().equals(spu.getStatus())) {
            throw new BizErrorException("商品不可售");
        }
        if (StrUtil.isNotBlank(skuId)) {
            MallSku sku = mallSkuService.get(skuId);
            if (sku == null || !spuId.equals(sku.getSpuId())) {
                throw new BizErrorException("SKU不可用");
            }
            if (!DisabledEnabledEnum.ENABLED.getValue().equals(sku.getStatus())) {
                throw new BizErrorException("SKU已下架");
            }
            return sku;
        }
        List<MallSku> list = mallSkuService.listEnabledSkus(spuId);
        if (list == null || list.isEmpty()) {
            throw new BizErrorException("商品暂无在售规格");
        }
        list.sort(java.util.Comparator.comparing(MallSku::getId, java.util.Comparator.nullsLast(String::compareTo)));
        return list.get(0);
    }

    private static Map<String, Object> toMobileProductRow(MallCartItemPortalRowVO r) {
        Map<String, Object> p = new LinkedHashMap<>();
        p.put("id", r.getId());
        p.put("cartItemId", r.getId());
        p.put("productId", r.getSpuId());
        p.put("spuId", r.getSpuId());
        p.put("skuId", r.getSkuId());
        String title = StrUtil.blankToDefault(r.getSkuName(), StrUtil.blankToDefault(r.getSpuName(), "商品"));
        p.put("name", title);
        p.put("price", formatMoney(r.getSkuPrice()));
        String img = StrUtil.blankToDefault(r.getSkuImage(), StrUtil.blankToDefault(r.getSpuMainImage(), ""));
        p.put("image", img);
        p.put("quantity", r.getQuantity() == null ? 1 : r.getQuantity());
        boolean sel = MallCartItemSelectedEnum.SELECTED.getValue().equals(r.getSelected());
        p.put("selected", sel);
        String spec = StrUtil.blankToDefault(r.getSpecInfo(), "");
        p.put("specText", spec);
        return p;
    }

    private static String formatMoney(BigDecimal p) {
        if (p == null) {
            return "0.00";
        }
        return p.setScale(2, RoundingMode.HALF_UP).toPlainString();
    }

    private MallCartItemQueryVO prepareQuery(MallCartItemQueryVO query) {
        MallCartItemQueryVO q = query != null ? query : new MallCartItemQueryVO();
        if (StrUtil.isNotBlank(q.getMemberKeyword())) {
            List<String> memberIds = memberService.findIdsByKeyword(q.getMemberKeyword().trim());
            q.setMemberKeyword(null);
            if (CollUtil.isEmpty(memberIds)) {
                return null;
            }
            q.setMemberIdIn(memberIds);
        }
        if (StrUtil.isNotBlank(q.getSpuName())) {
            List<String> spuIds = mallSpuService.findIdsBySpuNameLike(q.getSpuName().trim());
            q.setSpuName(null);
            if (CollUtil.isEmpty(spuIds)) {
                return null;
            }
            q.setSpuIdIn(spuIds);
        }
        if (StrUtil.isNotBlank(q.getSkuName())) {
            List<String> skuIds = mallSkuService.findIdsBySkuNameLike(q.getSkuName().trim());
            q.setSkuName(null);
            if (CollUtil.isEmpty(skuIds)) {
                return null;
            }
            q.setSkuIdIn(skuIds);
        }
        return q;
    }

    private void enrichListDisplay(List<MallCartItemListVO> rows) {
        if (CollUtil.isEmpty(rows)) {
            return;
        }
        memberService.enrichMemberDisplay(rows);
        List<String> spuIds = rows.stream().map(MallCartItemListVO::getSpuId).filter(StrUtil::isNotBlank).distinct().toList();
        List<String> skuIds = rows.stream().map(MallCartItemListVO::getSkuId).filter(StrUtil::isNotBlank).distinct().toList();
        Map<String, String> spuNameMap = mallSpuService.mapSpuNameByIds(spuIds);
        Map<String, String> skuNameMap = mallSkuService.mapSkuNameByIds(skuIds);
        for (MallCartItemListVO row : rows) {
            if (StrUtil.isNotBlank(row.getSpuId())) {
                row.setSpuName(spuNameMap.get(row.getSpuId()));
            }
            if (StrUtil.isNotBlank(row.getSkuId())) {
                row.setSkuName(skuNameMap.get(row.getSkuId()));
            }
        }
    }

    private PageRespVO<MallCartItemListVO> emptyPage(Page<MallCartItem> page) {
        PageRespVO<MallCartItemListVO> empty = new PageRespVO<>();
        empty.setRecords(Collections.emptyList());
        empty.setTotal(0L);
        empty.setPageNo(page.getPageNo());
        empty.setPageSize(page.getPageSize());
        empty.setPages(0L);
        return empty;
    }
}
