package com.ruoyi.common.core.aspect;

import com.ruoyi.common.core.annotation.CoordinateChange;
import com.ruoyi.common.core.utils.coordinate.Gps;
import com.ruoyi.common.core.utils.coordinate.PositionUtil;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

/**
 * 地理坐标转换AOP
 * 坐标格式(经度，纬度)
 */
@Aspect
@Component
public class CoordinateAspector {

    private static final String SEPARATOR = ",";

    @Around("@annotation(coordinateChange)")
    public Object doBefore(ProceedingJoinPoint point, CoordinateChange coordinateChange) throws Throwable {
        // 获取查询结果
        Object proceed = point.proceed();
        // 结果不为null时
        if (null != proceed){
            MethodSignature signature = (MethodSignature) point.getSignature();
            Type type = signature.getMethod().getGenericReturnType();
            if (CoordinateChange.CollectionFlag.IS_COLLECTION.equals(coordinateChange.isCollection())){
                // 集合
                Collection<?> collection = (Collection<?>) proceed;
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                Class<?> clz = null;
                for (Type actualTypeArgument : actualTypeArguments) {
                    clz = Class.forName(actualTypeArgument.getTypeName());
                }
                // 遍历赋值
                Class<?> finalClz = clz;
                collection.forEach(c->{
                    Field field = null;
                    try {
                        field = finalClz.getDeclaredField(coordinateChange.attributeName());
                        field.setAccessible(true);
                        String coordinateStr = (String)field.get(c);
                        if (StringUtils.isNotEmpty(coordinateStr)) {
                            // 坐标转换
                            String[] split = coordinateStr.split(SEPARATOR);
                            Gps gps = transformCoordinate(Double.parseDouble(split[0]), Double.parseDouble(split[1]), coordinateChange);
                            // 重新赋值
                            String newCoordinateStr = gps.getWgLon() + SEPARATOR + gps.getWgLat();
                            field.set(c, newCoordinateStr);
                        }
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                });
            }else if (CoordinateChange.CollectionFlag.NOT_COLLECTION.equals(coordinateChange.isCollection())){
                // 单个对象
                // 通过反射获取坐标
                Class<?> clz = Class.forName(type.getTypeName());
                Field field = clz.getDeclaredField(coordinateChange.attributeName());
                field.setAccessible(true);
                String coordinateStr = (String)field.get(proceed);
                if (StringUtils.isNotEmpty(coordinateStr)) {
                    // 坐标转换
                    String[] split = coordinateStr.split(SEPARATOR);
                    Gps gps = transformCoordinate(Double.parseDouble(split[0]), Double.parseDouble(split[1]), coordinateChange);
                    // 重新赋值
                    String newCoordinateStr = gps.getWgLon() + SEPARATOR + gps.getWgLat();
                    field.set(proceed, newCoordinateStr);
                }
            }
        }
        return proceed;
    }

    /**
     * 坐标转换
     * @param longitude 经度
     * @param latitude 纬度
     * @param coordinateChange 注解
     * @return 转换后坐标
     */
    private Gps transformCoordinate(double longitude, double latitude, CoordinateChange coordinateChange){
        if (coordinateChange.origin().equals(CoordinateChange.CoordinateType.WGS84)){
            if (coordinateChange.target().equals(CoordinateChange.CoordinateType.GCJ02)){
                return PositionUtil.gps84_To_Gcj02(latitude,longitude);
            }else if (coordinateChange.target().equals(CoordinateChange.CoordinateType.BD09)){
                Gps gps = PositionUtil.gps84_To_Gcj02(latitude, longitude);
                return PositionUtil.gcj02_To_Bd09(gps.getWgLat(),gps.getWgLon());
            }
        }else if (coordinateChange.origin().equals(CoordinateChange.CoordinateType.GCJ02)){
            if (coordinateChange.target().equals(CoordinateChange.CoordinateType.WGS84)){
                return PositionUtil.gcj02_To_Gps84(latitude,longitude);
            }else if (coordinateChange.target().equals(CoordinateChange.CoordinateType.BD09)){
                return PositionUtil.gcj02_To_Bd09(latitude,longitude);
            }
        }else if(coordinateChange.origin().equals(CoordinateChange.CoordinateType.BD09)){
            if (coordinateChange.target().equals(CoordinateChange.CoordinateType.GCJ02)){
                return PositionUtil.bd09_To_Gcj02(latitude,longitude);
            }else if (coordinateChange.target().equals(CoordinateChange.CoordinateType.WGS84)){
                Gps gps = PositionUtil.bd09_To_Gcj02(latitude,longitude);
                return PositionUtil.gcj02_To_Gps84(gps.getWgLat(), gps.getWgLon());
            }
        }
        return new Gps(latitude,longitude);
    }
}
