package com.ylx.massage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DateUtils;
import com.ylx.massage.domain.TGeoFence;
import com.ylx.massage.mapper.TGeoFenceMapper;
import com.ylx.massage.service.TGeoFenceService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

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

/**
 * 地理围栏服务实现类
 */
@Service
public class TGeoFenceServiceImpl extends ServiceImpl<TGeoFenceMapper, TGeoFence> implements TGeoFenceService {

    private static final BigDecimal MIN_LONGITUDE = new BigDecimal("-180");
    private static final BigDecimal MAX_LONGITUDE = new BigDecimal("180");
    private static final BigDecimal MIN_LATITUDE = new BigDecimal("-90");
    private static final BigDecimal MAX_LATITUDE = new BigDecimal("90");
    private static final int RISK_LOW = 1;
    private static final int RISK_MEDIUM = 2;
    private static final int RISK_HIGH = 3;
    private static final int NOT_DELETE = 0;

    @Override
    public Page<TGeoFence> pageGeoFence(Page<TGeoFence> page, TGeoFence geoFence) {
        LambdaQueryWrapper<TGeoFence> queryWrapper = buildQueryWrapper(geoFence);
        queryWrapper.orderByAsc(TGeoFence::getId);
        return this.page(page, queryWrapper);
    }

    @Override
    public List<TGeoFence> listMapGeoFence(TGeoFence geoFence) {
        LambdaQueryWrapper<TGeoFence> queryWrapper = buildQueryWrapper(geoFence);
        queryWrapper.select(TGeoFence::getId, TGeoFence::getCityCode, TGeoFence::getCityName,
                TGeoFence::getFenceName, TGeoFence::getAddress, TGeoFence::getLongitude,
                TGeoFence::getLatitude, TGeoFence::getRadiusKm, TGeoFence::getRiskLevel);
        queryWrapper.isNotNull(TGeoFence::getLongitude)
                .isNotNull(TGeoFence::getLatitude)
                .orderByAsc(TGeoFence::getId);
        return this.list(queryWrapper);
    }

    @Override
    public Boolean addGeoFence(TGeoFence geoFence) {
        validateGeoFenceParam(geoFence);
        geoFence.setId(null);
        geoFence.setIsDelete(NOT_DELETE);
        geoFence.setCreateTime(DateUtils.getNowDate());
        geoFence.setUpdateTime(DateUtils.getNowDate());

        boolean saved = this.save(geoFence);
        if (!saved) {
            throw new ServiceException("新增围栏失败");
        }
        return true;
    }

    @Override
    public Boolean updateGeoFence(TGeoFence geoFence) {
        validateUpdateParam(geoFence);

        TGeoFence exists = this.getById(geoFence.getId());
        if (exists == null) {
            throw new ServiceException("围栏不存在");
        }

        TGeoFence update = new TGeoFence();
        update.setId(geoFence.getId());
        update.setCityCode(geoFence.getCityCode());
        update.setCityName(geoFence.getCityName());
        update.setFenceName(geoFence.getFenceName());
        update.setFenceIntro(geoFence.getFenceIntro());
        update.setAddress(geoFence.getAddress());
        update.setLongitude(geoFence.getLongitude());
        update.setLatitude(geoFence.getLatitude());
        update.setRadiusKm(geoFence.getRadiusKm());
        update.setRiskLevel(geoFence.getRiskLevel());
        update.setUpdateTime(DateUtils.getNowDate());

        boolean updated = this.updateById(update);
        if (!updated) {
            throw new ServiceException("编辑围栏失败");
        }
        return true;
    }

    @Override
    public Boolean deleteGeoFence(TGeoFence geoFence) {
        Long id = getValidId(geoFence);
        TGeoFence exists = this.getById(id);
        if (exists == null) {
            throw new ServiceException("围栏不存在");
        }

        boolean removed = this.removeById(id);
        if (!removed) {
            throw new ServiceException("删除围栏失败");
        }
        return true;
    }

    @Override
    public List<TGeoFence> selectValidFences(String cityCode) {
        LambdaQueryWrapper<TGeoFence> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(cityCode), TGeoFence::getCityCode, cityCode)
                .eq(TGeoFence::getIsDelete, NOT_DELETE);
        return this.list(queryWrapper);
    }

    private void validateUpdateParam(TGeoFence geoFence) {
        if (geoFence == null) {
            throw new ServiceException("参数不能为空");
        }
        if (geoFence.getId() == null || geoFence.getId() <= 0) {
            throw new ServiceException("围栏ID不能为空");
        }
        validateGeoFenceParam(geoFence);
    }

    private Long getValidId(TGeoFence geoFence) {
        if (geoFence == null) {
            throw new ServiceException("参数不能为空");
        }
        if (geoFence.getId() == null || geoFence.getId() <= 0) {
            throw new ServiceException("围栏ID不能为空");
        }
        return geoFence.getId();
    }

    private void validateGeoFenceParam(TGeoFence geoFence) {
        if (geoFence == null) {
            throw new ServiceException("参数不能为空");
        }
        if (StringUtils.isBlank(geoFence.getCityCode())) {
            throw new ServiceException("城市编码不能为空");
        }
        if (StringUtils.isBlank(geoFence.getCityName())) {
            throw new ServiceException("城市名称不能为空");
        }
        if (StringUtils.isBlank(geoFence.getFenceName())) {
            throw new ServiceException("围栏名称不能为空");
        }
        if (StringUtils.isBlank(geoFence.getFenceIntro())) {
            throw new ServiceException("围栏介绍不能为空");
        }
        if (geoFence.getRadiusKm() == null || geoFence.getRadiusKm().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("围栏半径必须大于0");
        }
        if (!isValidRiskLevel(geoFence.getRiskLevel())) {
            throw new ServiceException("风险等级值不正确");
        }
        validateCoordinate(geoFence.getLongitude(), geoFence.getLatitude());
    }

    private boolean isValidRiskLevel(Integer riskLevel) {
        return riskLevel != null && (riskLevel == RISK_LOW || riskLevel == RISK_MEDIUM || riskLevel == RISK_HIGH);
    }

    /**
     * 构建查询条件。
     *
     * @param geoFence
     * @return LambdaQueryWrapper<TGeoFence>
     */
    private LambdaQueryWrapper<TGeoFence> buildQueryWrapper(TGeoFence geoFence) {
        LambdaQueryWrapper<TGeoFence> queryWrapper = new LambdaQueryWrapper<>();
        if (geoFence != null) {
            queryWrapper.eq(StringUtils.isNotBlank(geoFence.getCityCode()), TGeoFence::getCityCode, geoFence.getCityCode())
                    .like(StringUtils.isNotBlank(geoFence.getFenceName()), TGeoFence::getFenceName, geoFence.getFenceName())
                    .like(StringUtils.isNotBlank(geoFence.getAddress()), TGeoFence::getAddress, geoFence.getAddress());
        }
        return queryWrapper;
    }

    /**
     * 验证地理坐标栏中心点坐标是否有效。
     *
     * @param longitude 经度
     * @param latitude  纬度
     */
    private void validateCoordinate(BigDecimal longitude, BigDecimal latitude) {
        if (longitude == null) {
            throw new ServiceException("围栏中心点经度不能为空");
        }
        if (latitude == null) {
            throw new ServiceException("围栏中心点纬度不能为空");
        }
        if (longitude.compareTo(MIN_LONGITUDE) < 0 || longitude.compareTo(MAX_LONGITUDE) > 0) {
            throw new ServiceException("经度必须在-180到180之间");
        }
        if (latitude.compareTo(MIN_LATITUDE) < 0 || latitude.compareTo(MAX_LATITUDE) > 0) {
            throw new ServiceException("纬度必须在-90到90之间");
        }
    }
}
