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

import cn.hutool.core.bean.BeanUtil;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.scenic.dto.scenic.ScenicV2DTO;
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
import com.ycwl.basic.integration.common.response.PageResponse;
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.mobile.scenic.account.ScenicRegisterReq;
import com.ycwl.basic.model.mobile.scenic.account.ScenicRegisterRespVO;
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.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

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 DeviceIntegrationService deviceIntegrationService;
    @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);
        query.setStatus("1");
        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();
        // 通过zt-device服务获取设备统计
        PageResponse<DeviceV2DTO> deviceListResponse = deviceIntegrationService.getScenicActiveDevices(scenicId, 1, 1000);
        ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO();
        if (deviceListResponse != null && deviceListResponse.getList() != null) {
            scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size());
        } else {
            scenicDeviceCountVO.setTotalDeviceCount(0);
        }
        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());
        }
        
        // 通过zt-device服务获取设备统计
        PageResponse<DeviceV2DTO> deviceListResponse = deviceIntegrationService.getScenicActiveDevices(id, 1, 1000);
        ScenicDeviceCountVO scenicDeviceCountVO = new ScenicDeviceCountVO();
        if (deviceListResponse != null && deviceListResponse.getList() != null) {
            scenicDeviceCountVO.setTotalDeviceCount(deviceListResponse.getList().size());
        } else {
            scenicDeviceCountVO.setTotalDeviceCount(0);
        }
        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.getIsActive() == null || scenicAccount.getIsActive() != 1) {
            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 ApiResponse<ScenicRegisterRespVO> register(ScenicRegisterReq scenicRegisterReq) {
        // 验证手机号格式
        if (scenicRegisterReq.getPhone() == null || !scenicRegisterReq.getPhone().matches("^1[3-9]\\d{9}$")) {
            return ApiResponse.fail("手机号格式不正确");
        }
        
        // 验证密码不能为空
        if (scenicRegisterReq.getPassword() == null || scenicRegisterReq.getPassword().trim().isEmpty()) {
            return ApiResponse.fail("密码不能为空");
        }
        
        // 检查手机号是否已存在
        try {
            ScenicAccountEntity existingAccount = scenicAccountService.getScenicAccountByAccount(scenicRegisterReq.getPhone());
            if (existingAccount != null) {
                return ApiResponse.fail("该手机号已注册");
            }
        } catch (Exception e) {
            // 如果抛出异常说明账号不存在，可以继续注册
        }
        
        // 创建新账号
        ScenicAccountEntity newAccount = new ScenicAccountEntity();
        newAccount.setAccount(scenicRegisterReq.getPhone());
        newAccount.setPhone(scenicRegisterReq.getPhone());
        newAccount.setPassword(scenicRegisterReq.getPassword());
        newAccount.setIsActive(0); // 未激活状态
        newAccount.setStatus(1); // 正常状态
        newAccount.setCreateTime(new Date());
        newAccount.setUpdateTime(new Date());
        
        try {
            int result = scenicAccountService.addScenicAccount(newAccount);
            if (result > 0) {
                ScenicRegisterRespVO response = new ScenicRegisterRespVO();
                response.setId(newAccount.getId());
                response.setAccount(newAccount.getAccount());
                response.setPhone(newAccount.getPhone());
                response.setIsActive(newAccount.getIsActive());
                response.setMessage("注册成功，请等待后台激活");
                return ApiResponse.success(response);
            } else {
                return ApiResponse.fail("注册失败");
            }
        } catch (Exception e) {
            log.error("注册失败", e);
            return ApiResponse.fail("注册失败：" + e.getMessage());
        }
    }

    @Override
    public List<ScenicAppVO> scenicListByLnLa(ScenicIndexVO scenicIndexVO) {
        // 参数校验
        if (scenicIndexVO == null) {
            log.warn("scenicListByLnLa 接收到空参数");
            return Collections.emptyList();
        }
        if (scenicIndexVO.getLatitude() == null || scenicIndexVO.getLongitude() == null) {
            log.warn("scenicListByLnLa 缺少必要的经纬度参数, latitude={}, longitude={}",
                scenicIndexVO.getLatitude(), scenicIndexVO.getLongitude());
            return Collections.emptyList();
        }

        // 从 scenicRepository 获取所有景区（1000个）
        ScenicReqQuery query = new ScenicReqQuery();
        query.setPageNum(1);
        query.setPageSize(1000);
        List<ScenicV2DTO> scenicList = scenicRepository.list(query);

        if (scenicList == null || scenicList.isEmpty()) {
            log.info("未查询到任何景区数据");
            return Collections.emptyList();
        }

        List<ScenicAppVO> list = new ArrayList<>();

        // 为每个景区获取详细信息（包含经纬度）
        for (ScenicV2DTO scenicDTO : scenicList) {
            try {
                // ID 格式校验
                if (StringUtils.isBlank(scenicDTO.getId())) {
                    log.warn("景区 ID 为空，跳过该景区");
                    continue;
                }

                // 获取景区详细信息（包含经纬度）
                ScenicEntity scenicEntity = scenicRepository.getScenic(Long.parseLong(scenicDTO.getId()));
                if (scenicEntity == null) {
                    log.warn("景区详情查询失败, scenicId={}", scenicDTO.getId());
                    continue;
                }

                if (scenicEntity.getLatitude() == null || scenicEntity.getLongitude() == null) {
                    log.warn("景区缺少经纬度信息, scenicId={}, scenicName={}",
                        scenicEntity.getId(), scenicEntity.getName());
                    continue;
                }

                // 计算距离
                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);

                    // 获取设备数量
                    List<DeviceV2DTO> devices = deviceRepository.getAllDeviceByScenicId(scenicEntity.getId());
                    scenicAppVO.setDeviceNum(devices != null ? devices.size() : 0);

                    list.add(scenicAppVO);
                }
            } catch (NumberFormatException e) {
                log.error("景区 ID 格式错误，无法转换为 Long 类型, scenicId={}, error={}",
                    scenicDTO.getId(), e.getMessage());
            } catch (Exception e) {
                log.error("处理景区信息时发生异常, scenicId={}, error={}",
                    scenicDTO != null ? scenicDTO.getId() : "unknown", e.getMessage(), e);
            }
        }

        log.info("根据经纬度筛选景区完成, 输入坐标=({}, {}), 符合条件的景区数量={}",
            scenicIndexVO.getLatitude(), scenicIndexVO.getLongitude(), list.size());

        return list;
    }

    @Override
    public ApiResponse<List<DeviceRespVO>> getDevices(Long scenicId) {
        PageResponse<DeviceV2DTO> deviceV2ListResponse = deviceIntegrationService.listDevices(1, 1000, null, null, null, 1, scenicId);
        List<DeviceRespVO> deviceRespVOList = deviceV2ListResponse.getList().stream().map(device -> {
            DeviceRespVO deviceRespVO = new DeviceRespVO();
            deviceRespVO.setId(device.getId());
            deviceRespVO.setName(device.getName());
            deviceRespVO.setNo(device.getNo());

            DeviceConfigManager config = deviceRepository.getDeviceConfigManager(device.getId());
            deviceRespVO.setPreviewUrl(config.getString("preview_url"));
            deviceRespVO.setPreviewCoverUrl(config.getString("preview_cover_url"));
            return deviceRespVO;
        }).collect(Collectors.toList());
        for (DeviceRespVO deviceRespVO : deviceRespVOList) {
            DeviceEntity onlineStatus = deviceRepository.getOnlineStatus(deviceRespVO.getId());
            if (onlineStatus != null) {
                deviceRespVO.setUpdateAt(onlineStatus.getKeepaliveAt());
                deviceRespVO.setKeepaliveAt(onlineStatus.getKeepaliveAt());
                if (onlineStatus.getKeepaliveAt() == null) {
                    deviceRespVO.setOnline(0);
                } else 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) {
            ScenicV2DTO scenicBasic = scenicRepository.getScenicBasic(deviceRespVO.getScenicId());
            deviceRespVO.setScenicName(scenicBasic.getName());
            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);
    }
}
