package com.czg.service.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.czg.account.dto.PageDTO;
import com.czg.account.dto.shopinfo.*;
import com.czg.account.entity.*;
import com.czg.account.enums.BranchDataSyncMethodEnum;
import com.czg.account.enums.ShopTypeEnum;
import com.czg.account.service.*;
import com.czg.config.RabbitPublisher;
import com.czg.config.RedisCst;
import com.czg.constants.ParamCodeCst;
import com.czg.constants.ShopSwitchTypeEnum;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.resp.CzgResult;
import com.czg.sa.MyStpLogic;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.service.account.mapper.ShopUserMapper;
import com.czg.system.dto.SysParamsDTO;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgStrUtils;
import com.czg.utils.GeoUtil;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Slf4j
@DubboService
@CacheConfig(cacheNames = "shopInfo")
public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> implements ShopInfoService {
    @Resource
    private RabbitPublisher rabbitPublisher;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private ShopRegisterService shopRegisterService;
    @Resource
    private ShopTableService shopTableService;
    @Resource
    private ShopUserMapper shopUserMapper;
    @Resource
    private ShopExtendService shopExtendService;
    @Resource
    private RedisService redisService;
    @Resource
    private ShopPayTypeService shopPayTypeService;
    @Resource
    private FreeDineConfigService freeDineConfigService;
    @Resource
    private ShopConfigService shopConfigService;

    @DubboReference
    private SysParamsService sysParamsService;

    @Override
    public ShopInfo getById(Serializable id) throws CzgException {
        return shopConfigService.getShopInfoAndConfig((Long) id);
    }

    @Override
    public boolean checkSwitch(Long shopId, ShopSwitchTypeEnum switchType) throws ValidateException {
        AssertUtil.isNull(shopId, "店铺ID不能为空");
        ShopInfo shopInfo = getById(shopId);
        AssertUtil.isNull(shopInfo, "店铺不存在");
        return switchType.getValue(shopInfo);
    }

    private ShopInfo getShopInfo(Long shopId) {
        ShopInfo shopInfo = getById(shopId);
        if (shopInfo == null) {
            throw new CzgException("店铺不存在");
        }
        if (shopInfo.getExpireTime() != null && (LocalDateTime.now().isAfter(shopInfo.getExpireTime()))) {
            throw new CzgException("店铺已过期，请联系商家");
        }
        if (SystemConstants.OneZero.ZERO == shopInfo.getOnSale() || shopInfo.getStatus() != SystemConstants.OneZero.ONE) {
            throw new CzgException("店铺已停业，请联系商家");
        }

        shopInfo.setBookingSms(null);
        shopInfo.setOperationPwd(null);
        shopInfo.setBindAccount(null);
        return shopInfo;
    }

    @Override
    public Page<ShopDetailDTO> get(PageDTO pageDTO, String profiles, String phone, String shopName, Integer status, Integer isHeadShop) {
        QueryWrapper queryWrapper = new QueryWrapper();
        if (StrUtil.isNotBlank(profiles)) {
            queryWrapper.eq(ShopInfo::getProfiles, profiles);
        }
        if (StrUtil.isNotBlank(phone)) {
            queryWrapper.like(ShopInfo::getPhone, phone);
        }
        if (StrUtil.isNotBlank(shopName)) {
            queryWrapper.like(ShopInfo::getShopName, shopName);
        }
        if (status != null) {
            queryWrapper.eq(ShopInfo::getStatus, status);
        }
        if (isHeadShop != null) {
            queryWrapper.eq(ShopInfo::getIsHeadShop, isHeadShop);
        }

        List<ShopInfo> shopAllList = getMapper().selectListByQuery(query().select(ShopInfo::getId, ShopInfo::getShopName)
                .eq(ShopInfo::getIsHeadShop, 1).ne(ShopInfo::getShopType, ShopTypeEnum.ONLY.getValue()));
        Map<Long, String> shopKv = shopAllList.stream().collect(Collectors.toMap(ShopInfo::getId, ShopInfo::getShopName));
        queryWrapper.orderBy(ShopInfo::getCreateTime, false);
        Page<ShopDetailDTO> page = pageAs(new Page<>(pageDTO.page(), pageDTO.size()), queryWrapper, ShopDetailDTO.class);
        page.getRecords().forEach(shopInfo -> {
            ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
            BeanUtil.copyProperties(shopConfig, shopInfo);
            shopInfo.setHeadShopName(shopKv.get(shopInfo.getMainId()));
            SysUser sysUser = sysUserService.getById(shopInfo.getId());
            shopInfo.setAccount(sysUser.getAccount());
        });
        return page;
    }

    /**
     * 签约店铺
     * @param activateDuration  签约时长
     * @param amount            续期费用
     */
    private void activateShop(ShopInfo shopInfo, Integer activateDuration, BigDecimal amount) {
        // 签约/续期
        if (shopInfo.getExpireTime() != null && shopInfo.getExpireTime().isAfter(LocalDateTime.now())) {
            shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(shopInfo.getExpireTime()), activateDuration).toLocalDateTime());
        } else {
            shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(), activateDuration).toLocalDateTime());
        }
        ShopRegister register = new ShopRegister();
        register.setShopId(shopInfo.getId());
        register.setPeriodMonth(activateDuration);
        register.setAmount(amount);
        shopRegisterService.save(register);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(ShopInfoAddDTO shopInfoAddDTO) {
        // 如果店铺类型是单店，是否主店要设为否
        if (ShopTypeEnum.ONLY.getValue().equals(shopInfoAddDTO.getShopType())) {
            shopInfoAddDTO.setIsHeadShop(SystemConstants.OneZero.ONE);
            if (shopInfoAddDTO.getMainId() != null) {
                throw new CzgException("单店不允许设置主店ID");
            }
        } else {
            if (shopInfoAddDTO.getIsHeadShop() == null) {
                throw new CzgException("加盟店/连锁店请选择是否主店");
            }
            if (shopInfoAddDTO.getIsHeadShop() == SystemConstants.OneZero.ZERO && shopInfoAddDTO.getMainId() == null) {
                throw new CzgException("请选择一个店铺做为主店");
            }
            if (shopInfoAddDTO.getIsHeadShop() == SystemConstants.OneZero.ONE) {
                shopInfoAddDTO.setMainId(null);
            }
        }
        shopInfoAddDTO.setPhone(shopInfoAddDTO.getPhone().trim());
        if (StrUtil.isBlank(shopInfoAddDTO.getPhone())) {
            throw new CzgException("请输入手机号");
        }
        long count = sysUserService.queryChain().eq(SysUser::getAccount, shopInfoAddDTO.getAccountName()).count();
        if (count > 0) {
            throw new CzgException("账户已存在");
        }
        //校验密码长度和强度
        CzgStrUtils.checkPwd(shopInfoAddDTO.getAccountPwd());
        // 添加系统账号
        shopInfoAddDTO.setRoleId(shopInfoAddDTO.getRoleId() == null ? 2L : shopInfoAddDTO.getRoleId());
        SysUser sysUser = sysUserService.addUser(shopInfoAddDTO.getShopName(), shopInfoAddDTO.getAccountName(), shopInfoAddDTO.getAccountPwd(), shopInfoAddDTO.getPhone(), shopInfoAddDTO.getRoleId());

        // 保存店铺信息
        ShopInfo shopInfo = BeanUtil.copyProperties(shopInfoAddDTO, ShopInfo.class);
        shopInfo.setId(sysUser.getId());
        shopInfo.setStatus(1);
        if (StrUtil.isNotBlank(shopInfo.getProfiles())) {
            shopInfo.setProfiles("release");
        }
        save(shopInfo);
        if (shopInfoAddDTO.getActivateDuration() != null) {
            activateShop(shopInfo, shopInfoAddDTO.getActivateDuration(),shopInfoAddDTO.getActivateAmount());
        }
        // 增加支付方式
        shopPayTypeService.addInfo(shopInfo.getId());
        // 初始化积分霸王餐设置
        freeDineConfigService.getConfig(shopInfo.getId());
        updateById(shopInfo);
        syncSaveConfig(shopInfo, shopInfoAddDTO);

        rabbitPublisher.sendOrderDetailStatusMsg(shopInfo.getId().toString(), "add_shop");
        return true;
    }

    /**
     * 同步创建配置信息
     *
     * @param shopInfo 店铺信息实体
     * @param dto      新增店铺信息DTO
     */
    private void syncSaveConfig(ShopInfo shopInfo, ShopInfoAddDTO dto) {
        ShopConfig shopConfig = new ShopConfig();
        shopConfig.setId(shopInfo.getId());
        shopConfig.setMainId(shopInfo.getMainId());
        shopConfig.setIsEnableProdSync(0);
        shopConfig.setIsEnableVipSync(0);
        shopConfig.setIsEnableConsSync(0);
        shopConfig.setIsAllowAccountLogin(1);
        shopConfig.setRemark(null);
        shopConfig.setIsReturnPwd(0);
        shopConfig.setIsMemberInPwd(0);
        shopConfig.setIsMemberReturnPwd(0);
        shopConfig.setIsTableFee(1);
        shopConfig.setIsMemberPrice(0);
        shopConfig.setIsAccountPay(0);
        shopConfig.setBranchDataSyncMethod(null);
        if (dto.getIsHeadShop() == SystemConstants.OneZero.ONE) {
            shopConfig.setBranchDataSyncMethod(BranchDataSyncMethodEnum.AUTO.getValue());
        }
        shopConfigService.save(shopConfig);
    }

    /**
     * 同步修改配置信息
     *
     * @param shopInfo 店铺信息实体
     * @param dto      新增店铺信息DTO
     */
    private void syncUpdateConfig(ShopInfo shopInfo, ShopInfoEditDTO dto) {
        ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
        BeanUtil.copyProperties(dto, shopConfig);
        shopConfigService.updateById(shopConfig);
    }

    @Override
    @CacheEvict(key = "#shopInfoEditDTO.id")
    @Transactional(rollbackFor = Exception.class)
    public Boolean edit(ShopInfoEditDTO shopInfoEditDTO) {
        shopInfoEditDTO.setIsMemberPrice(null);
        ShopInfo shopInfo;
        if (!StpKit.USER.isAdmin()) {
            shopInfo = queryChain().eq(ShopInfo::getId, StpKit.USER.getShopId()).one();
        } else {
            shopInfo = getById(shopInfoEditDTO.getId());
        }
        if (shopInfo == null) {
            throw new CzgException("店铺不存在");
        }
        String shopType = shopInfo.getShopType();
        Long mainId = shopInfo.getMainId();
        Integer isHeadShop = shopInfo.getIsHeadShop();
        if (StrUtil.isEmpty(shopInfoEditDTO.getShopType()) || shopType.equals(shopInfoEditDTO.getShopType())) {
            // 原来是单店，现在不是单店，那么就允许修改，否则不允许修改
        } else if (ShopTypeEnum.ONLY.getValue().equals(shopType) && !ShopTypeEnum.ONLY.getValue().equals(shopInfoEditDTO.getShopType())) {
            if (shopInfoEditDTO.getIsHeadShop() == null) {
                throw new CzgException("加盟店/连锁店请选择是否主店");
            }
            if (shopInfoEditDTO.getIsHeadShop() == SystemConstants.OneZero.ZERO && shopInfoEditDTO.getMainId() == null) {
                throw new CzgException("请选择一个店铺做为主店");
            }
            if (shopInfoEditDTO.getIsHeadShop() == SystemConstants.OneZero.ONE) {
                if (mainId != null) {
                    throw new CzgException("数据错误：当前店铺是非主店，不允许随意切换为主店");
                }
            }
            if (isHeadShop == SystemConstants.OneZero.ONE && shopInfoEditDTO.getIsHeadShop() == SystemConstants.OneZero.ZERO) {
                throw new CzgException("数据错误：当前店铺是主店，不允许随意切换为非主店");
            }
        } else {
            throw new CzgException("禁止连锁店/加盟店修改为单店");
        }
        if (shopInfoEditDTO.getActivateDuration() != null) {
            activateShop(shopInfo, shopInfoEditDTO.getActivateDuration(),shopInfoEditDTO.getActivateAmount());
        }
        BeanUtil.copyProperties(shopInfoEditDTO, shopInfo);
        if (shopInfoEditDTO.getOperationPwd() != null) {
            String key = "%s%s:%s".formatted(RedisCst.SMS_CODE, shopInfo.getPhone(), "editShopInfoOpePwd");
            Object val = redisService.get(key);
            if (val instanceof String code && !shopInfoEditDTO.getCode().equals(code)) {
                throw new CzgException("验证码错误");
            }

            shopInfo.setOperationPwd(SecureUtil.md5(shopInfoEditDTO.getOperationPwd()));
            redisService.del(key);
        }
        if (updateById(shopInfo)) {
            syncUpdateConfig(shopInfo, shopInfoEditDTO);
            SysUser sysUser = sysUserService.getById(shopInfo.getId());
            boolean flag = false;
            if (!sysUser.getNickName().equals(shopInfo.getShopName())) {
                sysUser.setNickName(shopInfo.getShopName());
                flag = true;
            }

            if (!sysUser.getPhone().equals(shopInfo.getPhone())) {
                sysUser.setPhone(shopInfo.getPhone());
                flag = true;
            }

            if (flag) {
                sysUserService.updateById(sysUser);
            }
            rabbitPublisher.sendOrderDetailStatusMsg(shopInfo.getId().toString(), "shopInfoUpdate");
            return true;
        }
        return false;
    }

    @Override
    public ShopDetailDTO detail(Long id) throws CzgException {
        ShopInfo shopInfo = queryChain().eq(ShopInfo::getId, id == null ? StpKit.USER.getShopId() : id).one();
        if (shopInfo == null) {
            throw new CzgException("店铺信息不存在");
        }

        if (!StpKit.USER.isAdmin() && !Objects.equals(StpKit.USER.getShopId(), shopInfo.getId())) {
            throw new CzgException("店铺信息不存在");
        }
        ShopConfig shopConfig = shopConfigService.getById(shopInfo.getId());
        if (shopConfig == null) {
            throw new CzgException("店铺配置不存在");
        }
        ShopDetailDTO shopDetailDTO = BeanUtil.copyProperties(shopInfo, ShopDetailDTO.class);
        SysUser sysUser = sysUserService.getById(shopInfo.getId());
        shopDetailDTO.setAccount(sysUser.getAccount());
        CzgResult<SysParamsDTO> shopOrderPayBaseUrl = sysParamsService.getParamsByCode(ParamCodeCst.System.SHOP_ORDER_PAY_BASE_URL);
        shopDetailDTO.setPaymentQrcode(shopOrderPayBaseUrl.getData().getParamValue() + "?shopId=" + id);
        BeanUtil.copyProperties(shopConfig, shopDetailDTO);
        return shopDetailDTO;
    }

    @Override
    public ShopInfoByCodeDTO getByCode(String tableCode, String lat, String lng, boolean checkState) {
        ShopTable shopTable = shopTableService.queryChain().eq(ShopTable::getTableCode, tableCode).one();
        if (shopTable == null) {
            throw new CzgException("错误的台桌码");
        }

        if (checkState && !shopTable.canUseByStatus()) {
            throw new CzgException("台桌状态不可用");
        }
        ShopInfo shopInfo = getShopInfo(shopTable.getShopId());
        double distance = 0;
        if (StrUtil.isAllNotBlank(lat, lng, shopInfo.getLat(), shopInfo.getLng())) {
            // 计算距离，单位：米
            distance = GeoUtil.getDistance(Long.parseLong(shopInfo.getLat()), Long.parseLong(shopInfo.getLng()), Long.parseLong(lat), Long.parseLong(lng));
        }

        ShopUser shopUser = shopUserMapper.selectOneByQuery(new QueryWrapper().eq(ShopUser::getUserId, StpKit.USER.getLoginIdAsLong()));
        List<ShopExtend> shopExtends = shopExtendService.listInfo(shopInfo.getId(), null);
        Map<String, ShopExtend> shopExtendMap = shopExtends.stream().collect(Collectors.toMap(ShopExtend::getAutoKey, i -> i));
        return new ShopInfoByCodeDTO(distance, shopInfo, shopExtendMap, shopTable, shopUser != null && shopUser.getIsVip() != null && shopUser.getIsVip() == 1);
    }

    @Override
    public ShopInfoDetailDTO getDetail(Long shopId) {
        ShopInfo shopInfo = getShopInfo(shopId);
        List<ShopExtend> shopExtends = shopExtendService.listInfo(shopId, null);
        Map<String, ShopExtend> shopExtendMap = shopExtends.stream().collect(Collectors.toMap(ShopExtend::getAutoKey, i -> i));
        return new ShopInfoDetailDTO(shopInfo, shopExtendMap);
    }

    @Override
    public Page<ShopInfoSubVO> getSubList(String lat, String lng, float distance) {
        PageHelper.startPage(PageUtil.buildPageHelp());
        return PageUtil.convert(new PageInfo<>(mapper.getSubList(lng, lat, distance)));
    }

    @Override
    public Page<ShopDetailDTO> getShopByMainId(PageDTO pageDTO, String shopName, Integer status) {
        Long loginId = (Long) StpKit.USER.getLoginId();
        ShopInfo shopInfo = getById(loginId);
        QueryWrapper queryWrapper = new QueryWrapper();
        if (!"only".equals(shopInfo.getShopType())) {
            if (shopInfo.getIsHeadShop() != 1) {
                queryWrapper.eq(ShopInfo::getId, loginId);
            } else {
                queryWrapper.and(q -> {
                    q.eq(ShopInfo::getId, loginId).or(q1 -> {
                        q1.eq(ShopInfo::getMainId, loginId);
                    });
                });
            }
        } else {
            queryWrapper.eq(ShopInfo::getId, loginId);
        }
        Page<ShopDetailDTO> page = pageAs(new Page<>(pageDTO.page(), pageDTO.size()), queryWrapper, ShopDetailDTO.class);
        page.getRecords().forEach(dto -> {
            SysUser sysUser = sysUserService.getById(shopInfo.getId());
            dto.setAccount(sysUser.getAccount());
        });
        return page;
    }

    @Override
    public List<ShopBranchSelectDTO> findShopBranch(Long shopId) {
        Long mainIdByShopId = getMainIdByShopId(shopId);
        List<ShopBranchSelectDTO> list = new ArrayList<>();
        // 主店信息
        ShopInfo shopInfo = getById(mainIdByShopId);
        ShopBranchSelectDTO head = new ShopBranchSelectDTO();
        head.setShopId(shopInfo.getId());
        head.setShopName(shopInfo.getShopName());
        list.add(head);
        MyStpLogic.LoginType loginType = (MyStpLogic.LoginType) StpKit.USER.getSession().get("loginType");
        if (loginType.compareTo(MyStpLogic.LoginType.STAFF) == 0) {
            return list;
        }
        List<ShopInfo> branchList = mapper.selectListByQuery(query().select(ShopInfo::getId, ShopInfo::getShopName).eq(ShopInfo::getMainId, mainIdByShopId).orderBy(ShopInfo::getId, true));
        for (ShopInfo info : branchList) {
            ShopBranchSelectDTO branch = new ShopBranchSelectDTO();
            branch.setShopId(info.getId());
            branch.setShopName(info.getShopName());
            list.add(branch);
        }
        return list;
    }

    @Override
    public Long getMainIdByShopId(Long shopId) throws CzgException {
        ShopInfo shopInfo = this.getById(shopId);
        if (shopInfo == null) {
            throw new CzgException("店铺信息不存在");
        }
        return shopInfo.getMainId() == null ? shopId : shopInfo.getMainId();

    }

    @Override
    public List<ShopInfo> getByMainIdOrList(Long mainShopId, List<Long> shopIdList, String shopName) {
        QueryWrapper queryWrapper = new QueryWrapper().like(ShopInfo::getShopName, shopName);
        if (shopIdList == null) {
            queryWrapper.and(q -> {
                q.eq(ShopInfo::getMainId, mainShopId).or(q1 -> {
                    q1.eq(ShopInfo::getId, mainShopId);
                });
            });
        } else {
            shopIdList.add(mainShopId);
            queryWrapper.in(ShopInfo::getId, shopIdList);
        }

        return list(queryWrapper);
    }

    @CacheEvict(key = "#id")
    @Override
    public BigDecimal updateAmount(Long id, BigDecimal amount) {
        ShopInfo shopInfo = getShopInfo(id);
        if (shopInfo.getAmount().add(amount).compareTo(BigDecimal.ZERO) < 0) {
            throw new CzgException("更新失败");
        }
        boolean flag = mapper.updateAmount(id, amount);
        if (!flag) {
            throw new CzgException("更新失败");
        }
        return shopInfo.getAmount().add(amount);
    }


    @Override
    public List<Long> getShopIdList() {
        return mapper.getShopIdList();
    }


    private boolean convertToBoolean(Object fieldValue) throws ValidateException {
        if (fieldValue instanceof Boolean) {
            // Boolean 类型直接返回
            return (Boolean) fieldValue;
        } else if (fieldValue instanceof Integer intValue) {
            // Integer 类型按 1/0 规则转换
            if (intValue == 1) {
                return true;
            } else if (intValue == 0) {
                return false;
            } else {
                return false;
            }
        } else {
            // 不支持的类型抛异常
            throw new ValidateException("字段类型不支持，仅支持Boolean/Integer，当前类型：" + fieldValue.getClass().getSimpleName());
        }
    }
}
