package com.jeesharp.business.modules.marketing.memberTenant.application;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.marketing.memberTenant.convert.MemberTenantConvert;
import com.jeesharp.business.modules.marketing.memberTenant.dto.MemberTenantAssignRoleDTO;
import com.jeesharp.business.modules.marketing.memberTenant.dto.MemberTenantBindDTO;
import com.jeesharp.business.modules.marketing.memberTenant.dto.MemberTenantJoinDTO;
import com.jeesharp.business.modules.marketing.memberTenant.entity.MemberTenant;
import com.jeesharp.business.modules.marketing.memberTenant.enums.MemberTenantBindStatusEnum;
import com.jeesharp.business.modules.marketing.memberTenant.enums.MemberTenantJoinSourceEnum;
import com.jeesharp.business.modules.marketing.memberTenant.enums.MemberTenantRoleEnum;
import com.jeesharp.business.modules.marketing.memberTenant.service.MemberTenantService;
import com.jeesharp.business.modules.marketing.memberTenant.vo.MemberTenantExportVO;
import com.jeesharp.business.modules.marketing.memberTenant.vo.MemberTenantInfoVO;
import com.jeesharp.business.modules.marketing.memberTenant.vo.MemberTenantListVO;
import com.jeesharp.business.modules.marketing.memberTenant.vo.MemberTenantMobileVO;
import com.jeesharp.business.modules.marketing.memberTenant.vo.MemberTenantQueryVO;
import com.jeesharp.business.modules.marketing.tenant.mapper.MarketingTenantReadMapper;
import com.jeesharp.business.modules.marketing.tenant.vo.MarketingTenantBriefVO;
import com.jeesharp.business.modules.member.entity.Member;
import com.jeesharp.business.modules.member.service.MemberService;
import com.jeesharp.business.modules.member.vo.MemberDisplayVO;
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.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 店铺会员应用服务：编排会员-店铺关系、租户只读查询与会员展示补全。
 *
 * @author jeesharp
 * @since 2026-06-25
 */
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MemberTenantApplicationService {

    private final MemberTenantService memberTenantService;
    private final MemberService memberService;
    private final MarketingTenantReadMapper marketingTenantReadMapper;

    public MemberTenantInfoVO get(String id) {
        MemberTenant entity = memberTenantService.get(id);
        if (entity == null) {
            throw new BizErrorException("店铺会员关系不存在");
        }
        MemberTenantInfoVO vo = MemberTenantConvert.INSTANCE.toInfoVO(entity);
        applyTenantName(vo.getTenantId(), vo::setTenantName);
        memberService.enrichMemberDisplay(vo);
        return vo;
    }

    public PageRespVO<MemberTenantListVO> findPage(Page<MemberTenant> page, MemberTenantQueryVO query) {
        MemberTenantQueryVO prepared = prepareQuery(query);
        if (prepared == null) {
            return emptyPage(page);
        }
        Page<MemberTenant> result = memberTenantService.findPage(page, prepared);
        PageRespVO<MemberTenantListVO> pageVo = MemberTenantConvert.INSTANCE.toPageRespVO(result);
        enrichTenantName(pageVo.getRecords());
        memberService.enrichMemberDisplay(pageVo.getRecords());
        return pageVo;
    }

    public List<MemberTenantExportVO> findList(MemberTenantQueryVO query) {
        MemberTenantQueryVO prepared = prepareQuery(query);
        if (prepared == null) {
            return Collections.emptyList();
        }
        List<MemberTenant> list = memberTenantService.findList(prepared);
        List<MemberTenantExportVO> exportList = MemberTenantConvert.INSTANCE.toExportVOList(list);
        enrichExportRows(exportList, list);
        return exportList;
    }

    @Transactional(readOnly = false)
    public MemberTenantMobileVO joinMemberTenant(String memberId, MemberTenantJoinDTO dto) {
        if (StrUtil.isBlank(memberId)) {
            throw new BizErrorException("请先登录");
        }
        if (dto == null || StrUtil.isBlank(dto.getTenantCode())) {
            throw new BizErrorException("店铺租户编码不能为空");
        }
        MarketingTenantBriefVO tenant = marketingTenantReadMapper.getByTenantCode(dto.getTenantCode().trim());
        if (tenant == null) {
            throw new BizErrorException("店铺不存在或已停用");
        }
        if (tenant.getStatus() != null && tenant.getStatus() == 0) {
            throw new BizErrorException("店铺已停用");
        }

        Member member = memberService.get(memberId);
        if (member == null) {
            throw new BizErrorException("会员不存在");
        }

        String joinSource = StrUtil.blankToDefault(dto.getJoinSource(), MemberTenantJoinSourceEnum.QR_SCAN.getValue());
        MemberTenant existing = memberTenantService.getByMemberAndTenant(memberId, tenant.getId());
        if (existing != null && MemberTenantBindStatusEnum.BOUND.getValue().equals(existing.getBindStatus())) {
            return toMobileVO(existing, tenant.getTenantName());
        }

        LocalDateTime now = LocalDateTime.now();
        if (existing != null) {
            existing.setBindStatus(MemberTenantBindStatusEnum.BOUND.getValue());
            existing.setJoinSource(joinSource);
            existing.setChannelCode(dto.getChannelCode());
            existing.setJoinDate(now);
            existing.setUnbindDate(null);
            if (StrUtil.isBlank(existing.getMemberRole())) {
                existing.setMemberRole(MemberTenantRoleEnum.CUSTOMER.getValue());
            }
            existing.setMemberNo(member.getMemberNo());
            existing.setTenantCode(tenant.getTenantCode());
            existing.setTenantId(tenant.getId());
            memberTenantService.updateMemberTenant(existing);
            return toMobileVO(existing, tenant.getTenantName());
        }

        MemberTenant created = new MemberTenant();
        created.setMemberId(memberId);
        created.setMemberNo(member.getMemberNo());
        created.setTenantId(tenant.getId());
        created.setTenantCode(tenant.getTenantCode());
        created.setBindStatus(MemberTenantBindStatusEnum.BOUND.getValue());
        created.setJoinSource(joinSource);
        created.setChannelCode(dto.getChannelCode());
        created.setMemberRole(MemberTenantRoleEnum.CUSTOMER.getValue());
        created.setJoinDate(now);
        memberTenantService.createMemberTenant(created);
        return toMobileVO(created, tenant.getTenantName());
    }

    public List<MemberTenantMobileVO> listMyTenants(String memberId) {
        if (StrUtil.isBlank(memberId)) {
            return Collections.emptyList();
        }
        List<MemberTenant> boundList = memberTenantService.listBoundByMemberId(memberId);
        if (CollUtil.isEmpty(boundList)) {
            return Collections.emptyList();
        }
        Map<String, String> tenantNameMap = loadTenantNameMap(boundList);
        return boundList.stream()
                .map(item -> toMobileVO(item, tenantNameMap.get(item.getTenantId())))
                .collect(Collectors.toList());
    }

    public List<MemberTenantMobileVO> listMyClerkTenants(String memberId) {
        if (StrUtil.isBlank(memberId)) {
            return Collections.emptyList();
        }
        List<MemberTenant> clerkList = memberTenantService.listClerkTenantsByMemberId(memberId);
        if (CollUtil.isEmpty(clerkList)) {
            return Collections.emptyList();
        }
        Map<String, String> tenantNameMap = loadTenantNameMap(clerkList);
        return clerkList.stream()
                .map(item -> toMobileVO(item, tenantNameMap.get(item.getTenantId())))
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = false)
    public void assignRole(MemberTenantAssignRoleDTO dto) {
        memberTenantService.assignMemberRole(dto.getId(), dto.getMemberRole());
    }

    /**
     * 后台绑定会员到店铺（来源 ADMIN），并可设置店内角色。
     */
    @Transactional(readOnly = false)
    public MemberTenantInfoVO bindMember(MemberTenantBindDTO dto) {
        if (dto == null || StrUtil.isBlank(dto.getMemberKeyword())) {
            throw new BizErrorException("会员关键词不能为空");
        }
        if (StrUtil.isBlank(dto.getTenantCode())) {
            throw new BizErrorException("店铺编码不能为空");
        }
        List<String> memberIds = memberService.findIdsByKeyword(dto.getMemberKeyword().trim());
        if (CollUtil.isEmpty(memberIds)) {
            throw new BizErrorException("未找到匹配的会员");
        }
        if (memberIds.size() > 1) {
            throw new BizErrorException("匹配到多名会员，请使用手机号或会员编号精确查询");
        }
        String memberRole = StrUtil.blankToDefault(dto.getMemberRole(), MemberTenantRoleEnum.CUSTOMER.getValue());
        if (MemberTenantRoleEnum.fromValue(memberRole) == null) {
            throw new BizErrorException("店铺角色无效");
        }

        MemberTenantJoinDTO joinDTO = new MemberTenantJoinDTO();
        joinDTO.setTenantCode(dto.getTenantCode().trim());
        joinDTO.setChannelCode(dto.getChannelCode());
        joinDTO.setJoinSource(MemberTenantJoinSourceEnum.ADMIN.getValue());
        MemberTenantMobileVO joined = joinMemberTenant(memberIds.get(0), joinDTO);

        if (!StrUtil.equals(memberRole, joined.getMemberRole())) {
            memberTenantService.assignMemberRole(joined.getId(), memberRole);
        }
        return get(joined.getId());
    }

    private MemberTenantQueryVO prepareQuery(MemberTenantQueryVO query) {
        MemberTenantQueryVO q = query != null ? query : new MemberTenantQueryVO();
        if (StrUtil.isBlank(q.getMemberKeyword())) {
            return q;
        }
        List<String> memberIds = memberService.findIdsByKeyword(q.getMemberKeyword().trim());
        q.setMemberKeyword(null);
        if (CollUtil.isEmpty(memberIds)) {
            return null;
        }
        q.setMemberIdIn(memberIds);
        return q;
    }

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

    private void enrichTenantName(List<? extends MemberTenantListVO> rows) {
        if (CollUtil.isEmpty(rows)) {
            return;
        }
        Map<String, String> tenantNameMap = loadTenantNameMapFromRows(rows);
        for (MemberTenantListVO row : rows) {
            if (StrUtil.isBlank(row.getTenantName())) {
                row.setTenantName(tenantNameMap.get(row.getTenantId()));
            }
        }
    }

    private void enrichExportRows(List<MemberTenantExportVO> exportList, List<MemberTenant> entities) {
        if (CollUtil.isEmpty(exportList) || CollUtil.isEmpty(entities)) {
            return;
        }
        Map<String, String> tenantNameMap = loadTenantNameMap(entities);
        List<String> memberIds = entities.stream()
                .map(MemberTenant::getMemberId)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        Map<String, MemberDisplayVO> memberMap = memberService.mapDisplayByIds(memberIds);
        for (int i = 0; i < exportList.size(); i++) {
            MemberTenant entity = entities.get(i);
            MemberTenantExportVO export = exportList.get(i);
            if (StrUtil.isBlank(export.getTenantName())) {
                export.setTenantName(tenantNameMap.get(entity.getTenantId()));
            }
            if (StrUtil.isBlank(export.getTenantCode())) {
                export.setTenantCode(entity.getTenantCode());
            }
            MemberDisplayVO display = memberMap.get(entity.getMemberId());
            if (display != null) {
                export.setMemberNo(display.getMemberNo());
                export.setMemberNickname(display.getMemberNickname());
                export.setMemberMobile(display.getMemberMobile());
            }
        }
    }

    private void applyTenantName(String tenantId, java.util.function.Consumer<String> nameSetter) {
        if (StrUtil.isBlank(tenantId) || nameSetter == null) {
            return;
        }
        Map<String, String> tenantNameMap = loadTenantNameMapByIds(Collections.singletonList(tenantId));
        nameSetter.accept(tenantNameMap.get(tenantId));
    }

    private Map<String, String> loadTenantNameMapFromRows(List<? extends MemberTenantListVO> rows) {
        List<String> tenantIds = rows.stream()
                .map(MemberTenantListVO::getTenantId)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        return loadTenantNameMapByIds(tenantIds);
    }

    private Map<String, String> loadTenantNameMap(List<MemberTenant> rows) {
        List<String> tenantIds = rows.stream()
                .map(MemberTenant::getTenantId)
                .filter(StrUtil::isNotBlank)
                .distinct()
                .collect(Collectors.toList());
        return loadTenantNameMapByIds(tenantIds);
    }

    private Map<String, String> loadTenantNameMapByIds(List<String> tenantIds) {
        if (CollUtil.isEmpty(tenantIds)) {
            return Collections.emptyMap();
        }
        return marketingTenantReadMapper.listByIds(tenantIds).stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(MarketingTenantBriefVO::getId, MarketingTenantBriefVO::getTenantName, (a, b) -> a));
    }

    private MemberTenantMobileVO toMobileVO(MemberTenant entity, String tenantName) {
        MemberTenantMobileVO vo = MemberTenantConvert.INSTANCE.toMobileVO(entity);
        vo.setTenantName(tenantName);
        return vo;
    }
}
