package com.ycwl.basic.service.mobile.impl;

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.mapper.DeviceMapper;
import com.ycwl.basic.mapper.ExtraDeviceMapper;
import com.ycwl.basic.mapper.ScenicAccountMapper;
import com.ycwl.basic.model.jwt.JwtInfo;
import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
import com.ycwl.basic.model.mobile.scenic.ScenicDeviceCountVO;
import com.ycwl.basic.model.mobile.scenic.ScenicIndexVO;
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginReq;
import com.ycwl.basic.model.mobile.scenic.account.ScenicLoginRespVO;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.model.pc.device.resp.DeviceRespVO;
import com.ycwl.basic.model.pc.scenic.entity.ScenicAccountEntity;
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
import com.ycwl.basic.model.pc.scenic.req.ScenicReqQuery;
import com.ycwl.basic.model.pc.scenic.resp.ScenicRespVO;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.AppScenicService;
import com.ycwl.basic.service.pc.ScenicAccountService;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.ycwl.basic.constant.JwtRoleConstant.MERCHANT;

/**
 * @Author：longbinbin
 * @Date：2024/12/6 10:23
 */
@Slf4j
@Service
public class AppScenicServiceImpl implements AppScenicService {

    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ScenicAccountMapper scenicAccountMapper;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private ScenicAccountService scenicAccountService;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    private ExtraDeviceMapper extraDeviceMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ScenicRepository scenicRepository;

    @Override
    public ApiResponse<PageInfo<ScenicEntity>> pageQuery(ScenicReqQuery scenicReqQuery) {

        ScenicReqQuery query = new ScenicReqQuery();
        query.setPageSize(1000);
        List<ScenicV2DTO> scenicList = scenicRepository.list(query);
        List<ScenicEntity> list = scenicList.stream().map(scenic -> {
            return scenicRepository.getScenic(Long.valueOf(scenic.getId()));
        }).toList();
        PageInfo<ScenicEntity> pageInfo = new PageInfo<>(list);
        return ApiResponse.success(pageInfo);
    }

    @Override
    public ApiResponse<ScenicDeviceCountVO> deviceCountByScenicId(Long scenicId) {
        JwtInfo worker = JwtTokenUtil.getWorker();
        ScenicDeviceCountVO scenicDeviceCountVO = deviceMapper.deviceCountByScenicId(scenicId);
        return ApiResponse.success(scenicDeviceCountVO);
    }

    @Override
    public ApiResponse<ScenicRespVO> getDetails(Long id) {
        ScenicEntity scenic = scenicRepository.getScenic(id);
        ScenicRespVO scenicRespVO = new ScenicRespVO();
        
        // 将ScenicEntity的值通过set/get方式写入到ScenicRespVO
        if (scenic != null) {
            scenicRespVO.setId(scenic.getId());
            scenicRespVO.setName(scenic.getName());
            scenicRespVO.setPhone(scenic.getPhone());
            scenicRespVO.setLogoUrl(scenic.getLogoUrl());
            scenicRespVO.setCoverUrl(scenic.getCoverUrl());
            scenicRespVO.setIntroduction(scenic.getIntroduction());
            scenicRespVO.setLongitude(scenic.getLongitude());
            scenicRespVO.setLatitude(scenic.getLatitude());
            scenicRespVO.setRadius(scenic.getRadius());
            scenicRespVO.setProvince(scenic.getProvince());
            scenicRespVO.setCity(scenic.getCity());
            scenicRespVO.setArea(scenic.getArea());
            scenicRespVO.setAddress(scenic.getAddress());
            scenicRespVO.setKfCodeUrl(scenic.getKfCodeUrl());
        }
        
        ScenicDeviceCountVO scenicDeviceCountVO = deviceMapper.deviceCountByScenicId(id);
        scenicRespVO.setLensNum(scenicDeviceCountVO.getTotalDeviceCount());
        return ApiResponse.success(scenicRespVO);
    }

    @Override
    public ApiResponse<ScenicLoginRespVO> login(ScenicLoginReq scenicLoginReq) throws Exception {
        ScenicAccountEntity scenicAccount = scenicAccountService.getScenicAccountByAccount(scenicLoginReq.getAccount());
        if (scenicAccount == null) {
            return ApiResponse.fail("账号不存在");
        }
        if (scenicAccount.getStatus() == 0) {
            return ApiResponse.fail("账号已被禁用");
        }
        if (!scenicAccount.getPassword().equals(scenicLoginReq.getPassword())) {
            return ApiResponse.fail("密码错误");
        }

        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setName(scenicAccount.getName());
        jwtInfo.setAccount(scenicAccount.getAccount());
        jwtInfo.setUserId(scenicAccount.getId());
        jwtInfo.setRoleId(MERCHANT.type);
        String token = jwtTokenUtil.generateToken(jwtInfo, scenicAccount.getUpdateTime());

        ScenicLoginRespVO scenicLoginRespVO = new ScenicLoginRespVO();
        BeanUtil.copyProperties(scenicAccount,scenicLoginRespVO);
        List<Long> scenicIds = scenicAccountMapper.getAccountRelations(scenicAccount.getId());
        if (!scenicIds.isEmpty()) {
            scenicLoginRespVO.setScenicId(scenicIds);
        } else {
            scenicLoginRespVO.setScenicId(List.of(scenicAccount.getId()));
        }
        scenicLoginRespVO.setToken(token);
        return ApiResponse.success(scenicLoginRespVO);
    }

    @Override
    public List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO) {
        // 从 scenicRepository 获取所有景区（1000个）
        ScenicReqQuery query = new ScenicReqQuery();
        query.setPageNum(1);
        query.setPageSize(1000);
        List<ScenicV2DTO> scenicList = scenicRepository.list(query);
        
        List<ScenicAppVO> list = new ArrayList<>();
        
        // 为每个景区获取详细信息（包含经纬度）
        for (ScenicV2DTO scenicDTO : scenicList) {
            try {
                // 获取景区详细信息（包含经纬度）
                ScenicEntity scenicEntity = scenicRepository.getScenic(Long.parseLong(scenicDTO.getId()));
                if (scenicEntity != null && scenicEntity.getLatitude() != null && scenicEntity.getLongitude() != null) {
                    // 计算距离
                    BigDecimal distance = calculateDistance(
                        scenicIndexVO.getLatitude(), 
                        scenicIndexVO.getLongitude(),
                        scenicEntity.getLatitude(), 
                        scenicEntity.getLongitude()
                    );
                    
                    // 根据距离和范围筛选景区
                    if (scenicEntity.getRadius() != null && 
                        distance.compareTo(scenicEntity.getRadius().multiply(BigDecimal.valueOf(1_000L))) < 0) {
                        
                        // 转换为 ScenicAppVO
                        ScenicAppVO scenicAppVO = new ScenicAppVO();
                        scenicAppVO.setId(scenicEntity.getId());
                        scenicAppVO.setName(scenicEntity.getName());
                        scenicAppVO.setPhone(scenicEntity.getPhone());
                        scenicAppVO.setIntroduction(scenicEntity.getIntroduction());
                        scenicAppVO.setCoverUrl(scenicEntity.getCoverUrl());
                        scenicAppVO.setLongitude(scenicEntity.getLongitude());
                        scenicAppVO.setLatitude(scenicEntity.getLatitude());
                        scenicAppVO.setRadius(scenicEntity.getRadius());
                        scenicAppVO.setProvince(scenicEntity.getProvince());
                        scenicAppVO.setCity(scenicEntity.getCity());
                        scenicAppVO.setArea(scenicEntity.getArea());
                        scenicAppVO.setAddress(scenicEntity.getAddress());
                        scenicAppVO.setDistance(distance);
                        scenicAppVO.setDeviceNum(deviceRepository.getAllDeviceByScenicId(scenicEntity.getId()).size());
                        
                        list.add(scenicAppVO);
                    }
                }
            } catch (Exception e) {
                // 单个景区获取失败，继续处理下一个
                continue;
            }
        }
        
        return list;
    }

    @Override
    public ApiResponse<List<DeviceRespVO>> getDevices(Long scenicId) {
        List<DeviceRespVO> deviceRespVOList = deviceMapper.listByScenicIdWithWVP(scenicId);
        for (DeviceRespVO deviceRespVO : deviceRespVOList) {
            DeviceEntity onlineStatus = deviceRepository.getOnlineStatus(deviceRespVO.getId());
            if (onlineStatus != null) {
                deviceRespVO.setUpdateAt(onlineStatus.getKeepaliveAt());
                deviceRespVO.setKeepaliveAt(onlineStatus.getKeepaliveAt());
                if (new Date().getTime() - onlineStatus.getKeepaliveAt().getTime() > 300000) {
                    deviceRespVO.setOnline(0);
                } else {
                    deviceRespVO.setOnline(onlineStatus.getOnline());
                }
            } else {
                deviceRespVO.setOnline(0);
                deviceRespVO.setKeepaliveAt(null);
                deviceRespVO.setUpdateAt(null);
            }
        }
        List<DeviceRespVO> extraDeviceList = extraDeviceMapper.listExtraDeviceByScenicId(scenicId);
        for (DeviceRespVO deviceRespVO : extraDeviceList) {
            if (redisTemplate.hasKey("ext_device:online:"+deviceRespVO.getNo())) {
                String onlineTs = redisTemplate.opsForValue().get("ext_device:online:"+deviceRespVO.getNo());
                if (!StringUtils.isNumeric(onlineTs)) {
                    deviceRespVO.setOnline(0);
                    continue;
                }
                Long ts = Long.parseLong(onlineTs);
                Date keepaliveAt = new Date(ts*1000);
                deviceRespVO.setUpdateAt(keepaliveAt);
                deviceRespVO.setKeepaliveAt(keepaliveAt);
                deviceRespVO.setOnline(keepaliveAt.getTime() > System.currentTimeMillis()-1000*60*5 ? 1 : 0);
            } else {
                deviceRespVO.setOnline(0);
            }
        }
        deviceRespVOList.addAll(0, extraDeviceList);
        return ApiResponse.success(deviceRespVOList);
    }
    
    /**
     * 计算两点之间的距离（米）
     * 使用 Haversine 公式
     */
    private BigDecimal calculateDistance(BigDecimal lat1, BigDecimal lon1, BigDecimal lat2, BigDecimal lon2) {
        if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
            return BigDecimal.ZERO;
        }
        
        final double R = 6371000; // 地球半径（米）
        
        double lat1Rad = Math.toRadians(lat1.doubleValue());
        double lat2Rad = Math.toRadians(lat2.doubleValue());
        double deltaLat = Math.toRadians(lat2.subtract(lat1).doubleValue());
        double deltaLon = Math.toRadians(lon2.subtract(lon1).doubleValue());
        
        double a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
                Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                Math.sin(deltaLon/2) * Math.sin(deltaLon/2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        
        double distance = R * c;
        return BigDecimal.valueOf(distance);
    }
}
