package com.ruoyi.web.modules.merchant.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.merchant.constant.MerchantConstants;
import com.ruoyi.web.modules.merchant.domain.BizMerchant;
import com.ruoyi.web.modules.merchant.dto.MerchantCertStatusDTO;
import com.ruoyi.web.modules.merchant.dto.MerchantCreateDTO;
import com.ruoyi.web.modules.merchant.mapper.MerchantBindMapper;
import com.ruoyi.web.modules.merchant.service.IMerchantAccountBindService;
import com.ruoyi.web.modules.merchant.vo.MerchantAdminUserOptionVO;
import com.ruoyi.web.modules.merchant.vo.MerchantMemberOptionVO;
import com.ruoyi.web.modules.account.constant.MemberConstants;
import com.ruoyi.web.modules.account.util.MemberMobileUtils;
import com.ruoyi.web.modules.merchant.exception.MerchantBatchDeleteException;
import com.ruoyi.web.modules.merchant.facade.IMerchantOrderFacade;
import com.ruoyi.web.modules.merchant.facade.IMerchantShopFacade;
import com.ruoyi.web.modules.merchant.mapper.BizMerchantMapper;
import com.ruoyi.web.modules.merchant.service.IMerchantService;
import com.ruoyi.web.modules.merchant.support.BizCompleteEvaluator;
import com.ruoyi.web.modules.merchant.support.CertStatusTransition;
import com.ruoyi.web.modules.merchant.support.MerchantDisplayUtils;
import com.ruoyi.web.modules.merchant.vo.AllowedCertStatusVO;
import com.ruoyi.web.modules.merchant.vo.MerchantDeleteCheckVO;
import com.ruoyi.web.modules.merchant.vo.MerchantDetailVO;
import com.ruoyi.web.modules.merchant.vo.MerchantListVO;
import com.ruoyi.web.modules.merchant.vo.MerchantShopBriefVO;
import com.ruoyi.web.modules.merchant.vo.OpenShopCheckVO;

@Service
public class MerchantServiceImpl implements IMerchantService
{
    @Autowired
    private BizMerchantMapper merchantMapper;

    @Autowired
    private IMerchantOrderFacade orderFacade;

    @Autowired
    private IMerchantShopFacade shopFacade;

    @Autowired
    private IMerchantAccountBindService accountBindService;

    @Autowired
    private MerchantBindMapper merchantBindMapper;

    @Override
    public List<MerchantListVO> selectMerchantList(BizMerchant query)
    {
        if (query != null && StringUtils.isNotEmpty(query.getMerchantName()))
        {
            query.setMerchantNameQuery(query.getMerchantName());
        }
        List<MerchantListVO> rows = new ArrayList<>();
        for (BizMerchant m : merchantMapper.selectList(query))
        {
            MerchantListVO vo = toListVo(m);
            MerchantDeleteCheckVO check = buildDeleteCheck(m);
            vo.setCanDelete(check.isCanDelete());
            rows.add(vo);
        }
        return rows;
    }

    @Override
    public MerchantDetailVO selectMerchantDetail(Long merchantId)
    {
        BizMerchant m = requireMerchant(merchantId);
        MerchantDetailVO vo = new MerchantDetailVO();
        BeanUtils.copyProperties(m, vo);
        vo.setUnitName(MerchantDisplayUtils.unitName(m));
        vo.setPendingBizFields(BizCompleteEvaluator.pendingFields(m));
        vo.setAllowedCertStatuses(buildAllowedStatuses(m.getCertStatus()));
        vo.setCanEdit(canEdit(m));
        vo.setCanDelete(buildDeleteCheck(m).isCanDelete());
        vo.setShops(shopFacade.listShopsByMerchantId(merchantId));
        String name = StringUtils.isNotEmpty(m.getMerchantName()) ? m.getMerchantName() : vo.getUnitName();
        vo.setShopListUrl("/agri/shop/list?merchantName=" + name);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> insertMerchant(MerchantCreateDTO merchant, String operator)
    {
        stripBizFieldsOnInsert(merchant);
        validateSubjectOnInsert(merchant);
        Date now = new Date();
        merchant.setCertStatus(MerchantConstants.CERT_NORMAL);
        merchant.setCertTime(now);
        merchant.setBizComplete(MerchantConstants.BIZ_INCOMPLETE);
        merchant.setShopCount(0);
        merchant.setCreateBy(operator);
        merchantMapper.insert(merchant);
        accountBindService.bindAccountOnMerchantCreate(merchant.getMerchantId(), merchant, operator);
        Map<String, Object> data = new HashMap<>();
        List<String> expired = collectExpiredItems(merchant);
        if (!expired.isEmpty())
        {
            data.put("warnExpired", true);
            data.put("expiredItems", expired);
        }
        data.put("merchantId", merchant.getMerchantId());
        return data;
    }

    @Override
    public List<MerchantAdminUserOptionVO> searchAdminUserOptions(String keyword)
    {
        return merchantBindMapper.selectAdminUsersByKeyword(keyword,
                com.ruoyi.web.modules.merchant.constant.MerchantBindConstants.MERCHANT_ADMIN_ROLE_KEY);
    }

    @Override
    public List<MerchantMemberOptionVO> searchMemberOptions(String keyword)
    {
        List<MerchantMemberOptionVO> rows = merchantBindMapper.selectMembersByKeyword(keyword,
                com.ruoyi.web.modules.account.constant.MemberConstants.MEMBER_ROLE_KEY);
        for (MerchantMemberOptionVO vo : rows)
        {
            vo.setMobile(MemberMobileUtils.mask(vo.getMobile()));
        }
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> updateMerchant(BizMerchant merchant, String operator)
    {
        BizMerchant existing = requireMerchant(merchant.getMerchantId());
        assertEditable(existing);
        merchant.setCertStatus(null);
        if (StringUtils.isNotEmpty(merchant.getMerchantName())
                && merchantMapper.countByMerchantName(merchant.getMerchantName(), merchant.getMerchantId()) > 0)
        {
            throw new ServiceException("商户名称已存在");
        }
        merchant.setUpdateBy(operator);
        merchantMapper.update(merchant);
        BizMerchant latest = merchantMapper.selectById(merchant.getMerchantId());
        String oldComplete = existing.getBizComplete();
        String newComplete = BizCompleteEvaluator.evaluateCompleteFlag(latest);
        merchantMapper.updateBizComplete(merchant.getMerchantId(), newComplete);
        Map<String, Object> data = new HashMap<>();
        data.put("bizCompleteChanged", !StringUtils.equals(oldComplete, newComplete));
        data.put("bizComplete", newComplete);
        return data;
    }

    @Override
    public Map<String, Object> updateCertStatus(Long merchantId, MerchantCertStatusDTO dto, String operator)
    {
        BizMerchant existing = requireMerchant(merchantId);
        String target = dto.getCertStatus();
        if (!CertStatusTransition.canTransition(existing.getCertStatus(), target))
        {
            throw new ServiceException("不允许的认证状态变更");
        }
        if (!dto.isConfirmed())
        {
            Map<String, Object> data = new HashMap<>();
            data.put("needConfirm", true);
            data.put("confirmMessage", CertStatusTransition.confirmMessage(existing.getCertStatus(), target));
            return data;
        }
        merchantMapper.updateCertStatus(merchantId, target);
        Map<String, Object> data = new HashMap<>();
        data.put("needConfirm", false);
        return data;
    }

    @Override
    public MerchantDeleteCheckVO deleteCheck(Long merchantId)
    {
        return buildDeleteCheck(requireMerchant(merchantId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMerchantByIds(Long[] merchantIds, String operator)
    {
        if (merchantIds == null || merchantIds.length == 0)
        {
            throw new ServiceException("请选择要删除的商户");
        }
        List<String> reasons = new ArrayList<>();
        List<Long> okIds = new ArrayList<>();
        for (Long id : merchantIds)
        {
            BizMerchant m = merchantMapper.selectById(id);
            if (m == null)
            {
                reasons.add("商户不存在");
                continue;
            }
            MerchantDeleteCheckVO check = buildDeleteCheck(m);
            if (!check.isCanDelete())
            {
                reasons.addAll(check.getReasons());
            }
            else
            {
                okIds.add(id);
            }
        }
        if (!reasons.isEmpty())
        {
            throw new MerchantBatchDeleteException("部分商户不满足删除条件，操作已取消", reasons);
        }
        merchantMapper.logicDeleteByIds(okIds, operator);
    }

    @Override
    public List<MerchantListVO> selectSelectableList()
    {
        List<MerchantListVO> rows = new ArrayList<>();
        for (BizMerchant m : merchantMapper.selectSelectableList())
        {
            rows.add(toListVo(m));
        }
        return rows;
    }

    @Override
    public OpenShopCheckVO openShopCheck(Long merchantId)
    {
        OpenShopCheckVO vo = new OpenShopCheckVO();
        BizMerchant m = merchantMapper.selectById(merchantId);
        if (m == null)
        {
            vo.setAllowed(false);
            vo.setReason("商户已删除");
            return vo;
        }
        if (MerchantConstants.CERT_FROZEN.equals(m.getCertStatus()))
        {
            vo.setAllowed(false);
            vo.setReason("商户已冻结");
            return vo;
        }
        if (MerchantConstants.CERT_CANCELLED.equals(m.getCertStatus()))
        {
            vo.setAllowed(false);
            vo.setReason("商户已注销");
            return vo;
        }
        if (!MerchantConstants.BIZ_COMPLETE.equals(m.getBizComplete()))
        {
            vo.setAllowed(false);
            vo.setReason("经营信息未完善");
            return vo;
        }
        vo.setAllowed(true);
        return vo;
    }

    @Override
    public List<MerchantShopBriefVO> listShops(Long merchantId)
    {
        requireMerchant(merchantId);
        return shopFacade.listShopsByMerchantId(merchantId);
    }

    private MerchantDeleteCheckVO buildDeleteCheck(BizMerchant m)
    {
        MerchantDeleteCheckVO vo = new MerchantDeleteCheckVO();
        List<String> reasons = new ArrayList<>();
        if (MerchantConstants.CERT_CANCELLED.equals(m.getCertStatus()))
        {
            reasons.add("已注销商户不可删除");
        }
        if (m.getShopCount() != null && m.getShopCount() > 0)
        {
            reasons.add("请先删除该商户下全部店铺");
        }
        if (orderFacade.hasUnfinishedOrdersByMerchant(m.getMerchantId()))
        {
            reasons.add("存在未完成订单");
        }
        if (!canEdit(m) && !MerchantConstants.CERT_CANCELLED.equals(m.getCertStatus()))
        {
            // still allow delete check for frozen with shops - handled above
        }
        vo.setReasons(reasons);
        vo.setCanDelete(reasons.isEmpty());
        return vo;
    }

    private void stripBizFieldsOnInsert(BizMerchant m)
    {
        m.setMerchantName(null);
        m.setServicePhone(null);
        m.setBizRegionCode(null);
        m.setBizRegionName(null);
        m.setBizDetailAddress(null);
        m.setContactName(null);
        m.setContactPhone(null);
        m.setContactEmail(null);
        m.setBankName(null);
        m.setBankBranch(null);
        m.setBankAccount(null);
        m.setBusinessLicense(null);
        m.setAccountPermit(null);
    }

    private void validateSubjectOnInsert(BizMerchant m)
    {
        if (!MerchantConstants.TYPE_PERSON.equals(m.getMerchantType())
                && !MerchantConstants.TYPE_ENTERPRISE.equals(m.getMerchantType()))
        {
            throw new ServiceException("商户类型无效");
        }
        if (MerchantConstants.TYPE_ENTERPRISE.equals(m.getMerchantType()))
        {
            if (StringUtils.isEmpty(m.getLegalName()))
            {
                throw new ServiceException("请输入法人姓名");
            }
            if (StringUtils.isEmpty(m.getCompanyName()))
            {
                throw new ServiceException("请输入企业名称");
            }
            if (StringUtils.isNotEmpty(m.getCreditCode())
                    && merchantMapper.countByCreditCode(m.getCreditCode(), null) > 0)
            {
                throw new ServiceException("该统一社会信用代码已入驻");
            }
        }
        if (MerchantConstants.TYPE_PERSON.equals(m.getMerchantType()))
        {
            if (StringUtils.isEmpty(m.getPersonName()))
            {
                throw new ServiceException("请输入姓名");
            }
            if (StringUtils.isNotEmpty(m.getIdCardNo()) && merchantMapper.countByIdCardNo(m.getIdCardNo(), null) > 0)
            {
                throw new ServiceException("该证件号码已入驻");
            }
        }
    }

    private List<String> collectExpiredItems(BizMerchant m)
    {
        List<String> items = new ArrayList<>();
        Date today = new Date();
        if (MerchantConstants.TYPE_PERSON.equals(m.getMerchantType())
                && MerchantConstants.VALID_PERIOD_RANGE.equals(m.getIdValidType())
                && m.getIdValidEnd() != null && m.getIdValidEnd().before(today))
        {
            items.add("个人证件");
        }
        if (MerchantConstants.TYPE_ENTERPRISE.equals(m.getMerchantType())
                && MerchantConstants.VALID_PERIOD_RANGE.equals(m.getLicenseValidType())
                && m.getLicenseValidEnd() != null && m.getLicenseValidEnd().before(today))
        {
            items.add("企业营业期限");
        }
        return items;
    }

    private List<AllowedCertStatusVO> buildAllowedStatuses(String current)
    {
        List<AllowedCertStatusVO> list = new ArrayList<>();
        if (MerchantConstants.CERT_NORMAL.equals(current))
        {
            list.add(CertStatusTransition.buildOption(current, MerchantConstants.CERT_FROZEN, "已冻结"));
            list.add(CertStatusTransition.buildOption(current, MerchantConstants.CERT_CANCELLED, "已注销"));
        }
        else if (MerchantConstants.CERT_FROZEN.equals(current))
        {
            list.add(CertStatusTransition.buildOption(current, MerchantConstants.CERT_NORMAL, "正常"));
            list.add(CertStatusTransition.buildOption(current, MerchantConstants.CERT_CANCELLED, "已注销"));
        }
        else if (MerchantConstants.CERT_CANCELLED.equals(current))
        {
            list.add(CertStatusTransition.buildOption(current, MerchantConstants.CERT_NORMAL, "正常"));
        }
        return list;
    }

    private boolean canEdit(BizMerchant m)
    {
        return MerchantConstants.CERT_NORMAL.equals(m.getCertStatus())
                || MerchantConstants.CERT_FROZEN.equals(m.getCertStatus());
    }

    private void assertEditable(BizMerchant m)
    {
        if (MerchantConstants.CERT_CANCELLED.equals(m.getCertStatus()))
        {
            throw new ServiceException("商户已注销，不可编辑");
        }
    }

    private BizMerchant requireMerchant(Long merchantId)
    {
        BizMerchant m = merchantMapper.selectById(merchantId);
        if (m == null)
        {
            throw new ServiceException("商户不存在");
        }
        return m;
    }

    private MerchantListVO toListVo(BizMerchant m)
    {
        MerchantListVO vo = new MerchantListVO();
        vo.setMerchantId(m.getMerchantId());
        vo.setMerchantType(m.getMerchantType());
        vo.setUnitName(MerchantDisplayUtils.unitName(m));
        vo.setMerchantName(MerchantDisplayUtils.displayMerchantName(m));
        vo.setContactName(m.getContactName());
        vo.setContactPhone(m.getContactPhone());
        vo.setShopCount(m.getShopCount());
        vo.setCertStatus(m.getCertStatus());
        String label = DictUtils.getDictLabel(MerchantConstants.DICT_CERT_STATUS, m.getCertStatus());
        vo.setCertStatusLabel(StringUtils.isNotEmpty(label) ? label : CertStatusTransition.statusLabel(m.getCertStatus()));
        vo.setCertTime(m.getCertTime());
        vo.setCanEdit(canEdit(m));
        return vo;
    }
}
