package com.ruoyi.ss.store.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.map.GeoUtils;
import com.ruoyi.ss.carousel.service.CarouselService;
import com.ruoyi.ss.city.domain.City;
import com.ruoyi.ss.city.service.ICityService;
import com.ruoyi.ss.device.domain.Device;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.ss.equipment.domain.Equipment;
import com.ruoyi.ss.equipment.domain.EquipmentVO;
import com.ruoyi.ss.equipment.service.IEquipmentService;
import com.ruoyi.ss.room.domain.Room;
import com.ruoyi.ss.room.domain.RoomQuery;
import com.ruoyi.ss.room.domain.RoomVO;
import com.ruoyi.ss.room.service.IRoomAssembler;
import com.ruoyi.ss.room.service.IRoomService;
import com.ruoyi.ss.store.domain.*;
import com.ruoyi.ss.store.mapper.StoreMapper;
import com.ruoyi.ss.store.service.IStoreAssembler;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.ss.toilet.domain.Toilet;
import com.ruoyi.ss.toilet.domain.ToiletQuery;
import com.ruoyi.ss.toilet.domain.ToiletVO;
import com.ruoyi.ss.toilet.service.IToiletAssembler;
import com.ruoyi.ss.toilet.service.IToiletService;
import com.ruoyi.ss.user.domain.UserVO;
import com.ruoyi.ss.user.service.IUserService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.ruoyi.common.constant.ServiceConstants.*;
import static com.ruoyi.common.utils.SecurityUtils.getUserId;

/**
 * 店铺Service业务层处理
 *
 * @author qzz
 * @date 2024-11-20
 */
@Slf4j
@Service
public class StoreServiceImpl implements IStoreService
{
    @Autowired
    private StoreMapper storeMapper;

    @Resource
    private ICityService cityService;

    @Resource
    public IRoomService roomService;

    @Autowired
    private DeviceService smDeviceService;

    @Autowired
    private IRoomAssembler roomAssembler;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private IUserService userService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private IEquipmentService equipmentService;

    @Resource
    private IToiletService toiletService;

    @Autowired
    private IToiletAssembler toiletAssembler;

    /**
     * 查询店铺
     *
     * @param storeId 店铺主键
     * @return 店铺
     */
    @Override
    public StoreVO selectEStoreByStoreId(Long storeId)
    {
        return storeMapper.selectEStoreByStoreId(storeId);
    }

    /**
     * 查询店铺
     *
     * @param storeId 店铺主键
     * @return 店铺
     */
    @Override
    public StoreVO selectMchStoreByStoreId(Long storeId)
    {
        StoreVO storeVO = storeMapper.selectEStoreByStoreId(storeId);
        ServiceUtil.assertion(storeVO == null, "店铺不存在");

        // 大门
        Gate gate = new Gate();
        gate.setGateId(storeVO.getGateId());
        gate.setGateSn(storeVO.getGateSn());
        gate.setUnlockMode(storeVO.getUnlockMode());
        gate.setUnlockCondition(storeVO.getUnlockCondition());
        gate.setUnlockTime(storeVO.getUnlockTime());
        storeVO.setGate(gate);

        // 获取房间信息
        RoomQuery query = new RoomQuery();
        query.setStoreId(storeId);
        query.setType2(ROOM_TYPE2_PRIVATE_ROOM);
        List<RoomVO> roomS = roomService.selectERoomList(query);
        storeVO.setRoomList(roomS);
        roomAssembler.assembleDeviceInfo(roomS);

        // 获取大厅设施
        query.setType2(ROOM_TYPE2_LOBBY_DEVICE);
        List<RoomVO> hallList = roomService.selectERoomList(query);
        storeVO.setHallEquList(hallList);
        roomAssembler.assembleDeviceInfo(hallList);

        // 获取卫生间
        ToiletQuery toiletQuery = new ToiletQuery();
        toiletQuery.setStoreId(storeId);
        List<ToiletVO> toiletVOS = toiletService.selectToiletList(toiletQuery);
        storeVO.setToiletList(toiletVOS);
        toiletAssembler.assembleDevice(toiletVOS);

        storeVO.setIdleRoomNum(roomService.selectIdleRoomNum(storeId));
        storeVO.setIdleEquipmentNum(equipmentService.selectIdleEquipmentNumByStoreId(storeId));
        storeVO.setToiletNum(roomService.selectToiletNum(storeId));
        return storeVO;
    }

    /**
     * 查询店铺列表
     *
     * @param eStore 店铺
     * @return 店铺
     */
    @Override
    public List<StoreVO> selectEStoreList(StoreQuery eStore)
    {
        return storeMapper.selectEStoreList(eStore);
    }

    /**
     * 新增店铺
     *
     * @param eStore 店铺
     * @return 结果
     */
    @Override
    public int insertEStore(Store eStore)
    {
        if(StrUtil.isNotBlank(eStore.getCode())){
            ServiceUtil.assertion(storeMapper.checkCodeIsExist(eStore.getCode(), eStore.getStoreId()), "店铺码已存在，请重新生成");
        }
        if(!Objects.isNull(eStore.getTypeTags())){
            eStore.setType(eStore.getTypeTags().get(0));
        }
        Long merchantId = eStore.getMerchantId();
        if(merchantId == null){
            merchantId = getUserId();
        }
        eStore.setManagerPhone(eStore.getServerPhone());
        // 校验权限
        UserVO userVO = userService.selectUserById(merchantId);
        if(STORE_PERMISSION_SINGLE.equals(userVO.getMultiStore())){
            int i = storeMapper.selectCount(merchantId);
            ServiceUtil.assertion(i > 0, "您已经有一个店铺，不能再创建，请先升级多店权限再操作");
        }
        eStore.setMerchantId(merchantId);
        setCityId(eStore);
        eStore.setCreateTime(DateUtils.getNowDate());
        Boolean execute = transactionTemplate.execute(e -> {
            int i = storeMapper.insertEStore(eStore);
            ServiceUtil.assertion(i == 0, "新建店铺失败");
            // 创建卫生间
            createToilet(eStore);
            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("新建店铺失败");
        return 1;
    }

    // 创建卫生间
    private void createToilet(Store eStore) {
        // 默认新增一个卫生间
        Toilet toilet = new Toilet();
        toilet.setName("卫生间");
        toilet.setMerchantId(eStore.getMerchantId());
        toilet.setStoreId(eStore.getStoreId());
        toilet.setStoreName(eStore.getName());
        int i = toiletService.insertToilet(toilet);
        ServiceUtil.assertion(i==0,"新增卫生间失败");
    }

    /**
     * 修改店铺
     *
     * @param eStore 店铺
     * @return 结果
     */
    @Override
    public int updateEStore(Store eStore)
    {
        if(StrUtil.isNotBlank(eStore.getCode())){
            ServiceUtil.assertion(storeMapper.checkCodeIsExist(eStore.getCode(), eStore.getStoreId()), "店铺编号已存在");
        }
        eStore.setUpdateTime(DateUtils.getNowDate());
        setCityId(eStore);
        Boolean execute = transactionTemplate.execute(e -> {
            int i = storeMapper.updateEStore(eStore);
            ServiceUtil.assertion(i == 0, "修改店铺");

            // 同步修改店铺名称，则修改房间、设施、卫生间中的店铺名称
            StoreVO storeVO = storeMapper.selectEStoreByStoreId(eStore.getStoreId());
            if(ObjectUtil.isNotNull(eStore.getName()) && !eStore.getName().equals(storeVO.getName())){
                syncModifyStoreName(eStore.getStoreId(), eStore.getName());
            }
            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("新建店铺失败");

        return 1;
    }

    private void syncModifyStoreName(Long storeId, String storeName) {
        roomService.updateStoreName(storeId, storeName);
        equipmentService.updateStoreName(storeId, storeName);
        toiletService.updateStoreName(storeId, storeName);
    }

    private void setCityId(Store eStore) {
        if(eStore.getLng() != null && eStore.getLat()!= null){
            Long cityIdByLocation = cityService.getCityIdByLocation(eStore.getLng().toString(), eStore.getLat().toString());
            ServiceUtil.assertion(cityIdByLocation == null, "根据经纬度 [%s,%s]查询城市id错误", eStore.getLng(), eStore.getLat());
            eStore.setCityId(cityIdByLocation);
        }
    }

    /**
     * 批量删除店铺
     *
     * @param storeIds 需要删除的店铺主键
     * @return 结果
     */
    @Override
    public int deleteEStoreByStoreIds(Long[] storeIds)
    {
        return storeMapper.deleteEStoreByStoreIds(storeIds);
    }

    /**
     * 删除店铺信息
     *
     * @param storeId 店铺主键
     * @return 结果
     */
    @Override
    public int deleteEStoreByStoreId(Long storeId)
    {
        // todo 店铺下是否有设施，不能删除
        return storeMapper.deleteEStoreByStoreId(storeId);
    }

    /**
     * 根据定位获取附近店铺列表
     */
    @Override
    public List<StoreVO> getStoreListByLocation(StoreQuery query) {
        // 根据定位查询出是哪个城市，获取该城市下的所有店铺
        City city = cityService.getCityByLocation(query.getPhoneLon(), query.getPhoneLat());
        if(!Objects.isNull(city)){
            List<StoreVO> eStoreVOS = storeMapper.selectEStoreByCityId(city.getCityId());
            for (StoreVO eStoreVO : eStoreVOS) {
                eStoreVO.setDistance(getDistance(query.getPhoneLon(), query.getPhoneLat(), eStoreVO.getLng(), eStoreVO.getLat()));
            }
            return eStoreVOS;
        }
        return null;
    }

    /**
     * 根据城市id获取店铺列表
     */
    @Override
    public List<StoreVO> getStoreListByCityId(Long cityId) {
        return storeMapper.selectEStoreByCityId(cityId);
    }


    /**
     * 开大门
     */
    @Override
    public boolean openGate(Long storeId,String reason,boolean returnMac) {
        StoreVO storeVO = storeMapper.selectEStoreByStoreId(storeId);
        return smDeviceService.controlDoor(storeVO.getGateId(),storeVO.getUnlockTime(),storeVO.getUnlockMode(), true,reason,returnMac);
    }

    /**
     * 关大门
     */
    @Override
    public boolean closeGate(Long storeId,String reason) {
        StoreVO storeVO = storeMapper.selectEStoreByStoreId(storeId);
        return smDeviceService.switchDevice(storeVO.getGateId(), false,false,reason,false);
    }

    /**
     * 客服电话
     */
    @Override
    public ServerPhone getServicePhone(Long storeId) {
        StoreVO eStoreVO = storeMapper.selectEStoreByStoreId(storeId);
        ServerPhone serverPhone = new ServerPhone();
        if(!Objects.isNull(eStoreVO)){
            serverPhone.setStorePhone(eStoreVO.getServerPhone());
        }
        String platformPhone = configService.selectConfigByKey("ss.platform.phone");
        serverPhone.setPlatformPhone(platformPhone);
        return serverPhone;
    }

    /**
     * 查看可用门店
     */
    @Override
    public List<StoreVO> getAvailableStores(Long storeId) {
        StoreVO eStoreVO = storeMapper.selectEStoreByStoreId(storeId);
        return storeMapper.getStoreListByMerchantId(eStoreVO.getMerchantId());
    }

    /**
     * 绑定大门
     */
    @Override
    public int bandGate(StoreDTO dto) {
        // 根据sn查询设备
        // 如果deviceId不存在,则用sn查询设备
        ServiceUtil.assertion(StringUtils.isBlank(dto.getSn()) && dto.getDeviceId() == null, "设备sn或设备id不能同时为空");
        DeviceVO deviceVO = null;
        if (dto.getDeviceId() == null) {
            deviceVO = smDeviceService.selectBySn(dto.getSn());
        }else{
            deviceVO = smDeviceService.selectById(dto.getDeviceId());
        }
        ServiceUtil.assertion(deviceVO == null, "设备不存在");
        ServiceUtil.assertion(deviceVO.getUserId() != null && !SecurityUtils.isAdmin(getUserId()) && !deviceVO.getUserId().equals(getUserId()), "不是您的设备请勿操作！");

        StoreVO storeVO = storeMapper.selectEStoreByStoreId(dto.getStoreId());
        ServiceUtil.assertion(storeVO == null, "店铺不存在");
        StoreVO updateStore = new StoreVO();
        updateStore.setStoreId(storeVO.getStoreId());
        updateStore.setGateId(deviceVO.getDeviceId());
        updateStore.setGateSn(deviceVO.getSn());

        Device device = new Device();
        device.setPlacementStatus(DEVICE_PLACEMENT_STATUS_PLACED);
        device.setPlacementType(FACILITY_TYPE_GATE);
        device.setDeviceId(deviceVO.getDeviceId());
        device.setStoreId(storeVO.getStoreId());

        Boolean execute = transactionTemplate.execute(e -> {
            // 下架原设备
            Long gateId = storeVO.getGateId();
            if(gateId != null){
                int offline = smDeviceService.offline(gateId);
                ServiceUtil.assertion(offline == 0, "下架原设备失败");
            }

            // 更新店铺
            int i = storeMapper.updateEStore(updateStore);
            ServiceUtil.assertion(i == 0, "绑定大门失败");

            // 更新设备
            int i1 = smDeviceService.updateSmDevice(device);
            ServiceUtil.assertion(i1 == 0, "绑定大门更新设备失败");
            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("微信支付回调失败");

        return 1;
    }

    private int createGate(Long storeId, String storeName) {
        Equipment equipment = new Equipment();
        equipment.setName("大门");
        equipment.setStoreId(storeId);
        equipment.setStoreName(storeName);
        equipment.setType(FACILITY_TYPE_GATE);
        int i = equipmentService.insertEquipment(equipment);
        ServiceUtil.assertion(i==0,"绑定大门失败");
        return i;
    }

    /**
     * 更新门店类型标签
     */
    @Override
    public int updateStoreTypeTags(Long storeId, String type) {
        //该店铺下是否存在该房间标签，不存在则添加后更新，存在则跳过
        boolean isTypeTags = storeMapper.isExistTypeTags(storeId,type);
        if(!isTypeTags){
            return storeMapper.updateStoreTypeTags(storeId,type);
        }
        return 1;
    }

    /**
     * 门禁授权
     */
    @Override
    public int gateAuth(GateAuthDTO dto) {
        Store store = new Store();
        store.setStoreId(dto.getStoreId());
        store.setUnlockCondition(dto.getUnlockCondition());
        store.setUnlockMode(dto.getUnlockMode());
        store.setUnlockTime(dto.getUnlockTime());
        store.setCode(dto.getCode());
        return storeMapper.updateEStore(store);
    }

    /**
     * 下架设备（根据设备id）
     * @param deviceId 设备id
     * @return String
     */
    @Override
    public int offlineDeviceByDeviceId(Long deviceId) {
        return storeMapper.offlineDeviceByDeviceId(deviceId);
    }

    /**
     * 获取用户已创建店铺数量
     * @param userId 用户id
     * @return int
     */
    @Override
    public int selectCount(Long userId) {
        return storeMapper.selectCount(userId);
    }

    /**
     * 根据商户id获取店铺id
     * @param mchId 商户id
     * @return Long
     */
    @Override
    public Long selectStoreIdByMerchantId(Long mchId) {
        return storeMapper.selectStoreIdByMerchantId(mchId);
    }

    /**
     * code交换id
     */
    @Override
    public Long getId(String storeCode) {
        return storeMapper.getId(storeCode);
    }

    private Double getDistance(String phoneLon, String phoneLat, BigDecimal lng, BigDecimal lat) {
        double[] point1 = {Double.parseDouble(phoneLon), Double.parseDouble(phoneLat)};
        double[] point2 = {lng.doubleValue(), lat.doubleValue()};
        double distanceInMeters = GeoUtils.haversineDistance(point1, point2);
        return Math.round((distanceInMeters / 1000) * 10) / 10.0;
    }
}
