package com.ttstd.dialer.manager;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
import android.text.TextUtils;

import androidx.core.app.ActivityCompat;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.jeremyliao.liveeventbus.LiveEventBus;
import com.tencent.mmkv.MMKV;
import com.ttstd.dialer.config.CommonConfig;
import com.ttstd.dialer.gson.GsonUtils;
import com.ttstd.dialer.utils.Logger;
import com.ttstd.dialer.utils.SystemUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

public class MapManager {
    private static final String TAG = "MapManager";
    private static final String[] REQUIRED_PERMISSIONS = {
            android.Manifest.permission.ACCESS_FINE_LOCATION,
            android.Manifest.permission.ACCESS_COARSE_LOCATION
    };

    // 线程安全的单例模式（双重检查锁）
    @SuppressLint("StaticFieldLeak")
    private static volatile MapManager sInstance;
    private final Context mContext; // 使用Application Context避免内存泄漏
    private final MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
    private LocationClient mLocationClient;
    private LocationClientOption mOption;
    // 线程安全的回调列表
    private final List<OnLocationListener> mListeners = new CopyOnWriteArrayList<>();

    // 定位结果回调接口
    public interface OnLocationListener {
        void onLocationSuccess(BDLocation location); // 定位成功

        void onLocationFailure(String errorMsg);    // 定位失败
    }

    private MapManager(Context context) {
        // 使用Application Context，避免持有Activity导致内存泄漏
        this.mContext = context.getApplicationContext();
    }

    // 初始化单例（线程安全）
    public static void init(Context context) {
        if (context == null) {
            throw new RuntimeException("Context cannot be null");
        }
        if (sInstance == null) {
            synchronized (MapManager.class) {
                if (sInstance == null) {
                    sInstance = new MapManager(context);
                }
            }
        }
    }

    public static MapManager getInstance() {
        if (sInstance == null) {
            throw new IllegalStateException("MapManager must be initialized first with init(Context)");
        }
        return sInstance;
    }

    /**
     * 初始化定位客户端（包含权限检查）
     */
    public void initMap() {
        if (!checkLocationPermissions()) {
            Logger.e(TAG, "Location permissions are missing");
            notifyLocationFailure("缺少定位权限，请先授予权限");
            return;
        }

        try {
            // 设置系统定位参数（抽取为独立方法）
            setupSystemLocationSettings();
        } catch (Exception e) {
            Logger.e(TAG, "Failed to setup system location settings", e.getMessage());
            notifyLocationFailure("系统定位设置失败：" + e.getMessage());
        }
        LocationClient.setAgreePrivacy(true);
        if (mLocationClient == null) {
            try {
                mLocationClient = new LocationClient(mContext);
                mLocationClient.setLocOption(getDefaultLocationClientOption());
                mLocationClient.registerLocationListener(mLocationListener);
            } catch (Exception e) {
                e.printStackTrace();
                Logger.e(TAG, "initMap: " + e.getMessage());
            }
        }

    }


    public void startLocation() {
        // 确保先停止再启动，避免重复启动
        if (mLocationClient.isStarted()) {
            mLocationClient.stop();
        }
        mLocationClient.start();
    }

    /**
     * 检查定位权限
     */
    private boolean checkLocationPermissions() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true; // 6.0以下默认有权限
        }
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ActivityCompat.checkSelfPermission(mContext, permission)
                    != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 配置系统定位参数（抽取重复代码）
     */
    private void setupSystemLocationSettings() {
//        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.ASSISTED_GPS_ENABLED, 1);
        Settings.Global.putInt(mContext.getContentResolver(), "assisted_gps_enabled", 1);
        // 合并定位提供者设置（原代码重复设置会覆盖，改为追加）
        String providers = Settings.Secure.getString(mContext.getContentResolver(),
                Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        if (TextUtils.isEmpty(providers)) {
            providers = "gps,network";
        } else {
            if (!providers.contains("gps")) providers += ",gps";
            if (!providers.contains("network")) providers += ",network";
        }
        Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, providers);
    }

    /**
     * 获取定位客户端（懒加载）
     */
    public LocationClient getLocationClient() {
        if (mLocationClient == null) {
            initMap();
        }
        return mLocationClient;
    }

    /**
     * 配置定位参数（允许外部自定义）
     */
    public void setLocationOption(LocationClientOption option) {
        if (option != null && mLocationClient != null) {
            mOption = option;
            mLocationClient.setLocOption(option);
        }
    }

    /**
     * 默认定位参数配置（修复重复设置问题）
     */
    public LocationClientOption getDefaultLocationClientOption() {
        if (mOption == null) {
            mOption = new LocationClientOption();
            mOption.setCoorType("bd09ll"); // 百度坐标系（配合百度地图使用）
            mOption.setScanSpan(0); // 仅定位一次（0表示单次定位）
            mOption.setIsNeedAddress(true); // 需要地址信息
            mOption.setIsNeedLocationDescribe(true); // 需要地址描述
            mOption.setNeedDeviceDirect(false); // 不需要设备方向
            mOption.setLocationNotify(false); // 不频繁输出GPS结果
            mOption.setIgnoreKillProcess(true); // 定位服务独立进程
            mOption.setIsNeedLocationPoiList(true); // 需要POI结果
            mOption.SetIgnoreCacheException(false); // 收集错误信息
            mOption.setLocationMode(LocationClientOption.LocationMode.Battery_Saving); // 低功耗模式
            mOption.setIsNeedAltitude(false); // 不需要海拔信息
        }
        return mOption;
    }

    /**
     * 注册定位回调
     */
    public void registerLocationListener(OnLocationListener listener) {
        if (listener != null && !mListeners.contains(listener)) {
            mListeners.add(listener);
        }
    }

    /**
     * 反注册定位回调（避免内存泄漏）
     */
    public void unregisterLocationListener(OnLocationListener listener) {
        if (listener != null) {
            mListeners.remove(listener);
        }
    }

    /**
     * 通知所有监听器定位成功
     */
    private void notifyLocationSuccess(BDLocation location) {
        for (OnLocationListener listener : mListeners) {
            try {
                listener.onLocationSuccess(location);
            } catch (Exception e) {
                Logger.e(TAG, "Error in onLocationSuccess callback", e.getMessage());
            }
        }
    }

    /**
     * 通知所有监听器定位失败
     */
    private void notifyLocationFailure(String errorMsg) {
        for (OnLocationListener listener : mListeners) {
            try {
                listener.onLocationFailure(errorMsg);
            } catch (Exception e) {
                Logger.e(TAG, "Error in onLocationFailure callback", e.getMessage());
            }
        }
    }

    /**
     * 存储定位结果（解耦存储逻辑）
     */
    private void saveLocationResult(BDLocation location) {
        if (location == null) return;
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_MAP_ADDRESS_KEY, location.getAddrStr());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_MAP_LOCATION_DESCRIBE_KEY, location.getLocationDescribe());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_PROVINCE_KEY, location.getProvince());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_CITY_KEY, location.getCity());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_DISTRICT_KEY, location.getDistrict());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_TOWN_KEY, location.getTown());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_STREET_KEY, location.getStreet());

        mMMKV.encode(CommonConfig.CURRENT_LOCATION_LONGITUDE_KEY, location.getLongitude());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_LATITUDE_KEY, location.getLatitude());
        mMMKV.encode(CommonConfig.CURRENT_LOCATION_AD_CODE_KEY, location.getAdCode());

//        mMMKV.encode(CommonConfig.CURRENT_LOCATION_LOCATION_ID_KEY, location.getLocationID());

        mMMKV.encode("MapError", "-");

        Map<String, Object> params = new LinkedHashMap<>();
        params.put("sn", SystemUtils.getSerial());
        params.put("address", location.getAddrStr());
        params.put("location_describe", location.getLocationDescribe());
        params.put("longitude", location.getLongitude());
        params.put("latitude", location.getLatitude());
        params.put("ad_code", location.getAdCode());
        params.put("coor_type", location.getCoorType());

        Logger.e(TAG, "saveLocationResult", "location = " + GsonUtils.toJSONString(location));

        WeatherManager.getInstance().setAdCode(location.getAdCode());

        LiveEventBus.get(CommonConfig.LOCATION_CHANGED_KEY)
                .post(location);
    }

    /**
     * 存储定位错误信息
     */
    private void saveLocationError(String errorMsg) {
        mMMKV.encode("MapError", errorMsg);
    }

    // 百度定位回调
    private final BDAbstractLocationListener mLocationListener = new BDAbstractLocationListener() {
        @Override
        public void onReceiveLocation(BDLocation location) {
            if (location == null) {
                String error = "定位结果为空";
                Logger.e(TAG, "onReceiveLocation", error);
                saveLocationError(error);
                notifyLocationFailure(error);
                stopLocation();
                return;
            }

            switch (location.getLocType()) {
                case BDLocation.TypeGpsLocation:
                case BDLocation.TypeNetWorkLocation:
                case BDLocation.TypeOffLineLocation:
                    Logger.e(TAG, "onReceiveLocation", "定位成功: " + location.getAddrStr() + location.getLocationDescribe());
                    saveLocationResult(location);
                    notifyLocationSuccess(location);
                    break;
                case BDLocation.TypeServerError:
                    String serverError = "服务端定位失败，请反馈问题";
                    Logger.e(TAG, "onReceiveLocation", serverError);
                    saveLocationError(serverError);
                    notifyLocationFailure(serverError);
                    break;
                case BDLocation.TypeNetWorkException:
                    String networkError = "网络异常导致定位失败，请检查网络";
                    Logger.e(TAG, "onReceiveLocation", networkError);
                    saveLocationError(networkError);
                    notifyLocationFailure(networkError);
                    break;
                case BDLocation.TypeCriteriaException:
                    String criteriaError = "无法获取定位依据，请检查设备状态";
                    Logger.e(TAG, "onReceiveLocation", criteriaError);
                    saveLocationError(criteriaError);
                    notifyLocationFailure(criteriaError);
                    break;
                default:
                    String unknownError = "未知定位错误: " + location.getLocType();
                    Logger.e(TAG, "onReceiveLocation", unknownError);
                    saveLocationError(unknownError);
                    notifyLocationFailure(unknownError);
                    break;
            }

            // 单次定位完成后停止（如果是单次定位模式）
            if (mOption != null && mOption.getScanSpan() == 0) {
                stopLocation();
            }
        }

        @Override
        public void onLocDiagnosticMessage(int locType, int diagnosticType, String diagnosticMessage) {
            super.onLocDiagnosticMessage(locType, diagnosticType, diagnosticMessage);
            String errorMsg = "定位诊断: " + diagnosticMessage;
            Logger.e(TAG, "onLocDiagnosticMessage", errorMsg);
            saveLocationError(errorMsg);
            notifyLocationFailure(errorMsg);
        }
    };

    /**
     * 停止定位并释放资源
     */
    public void stopLocation() {
        if (mLocationClient != null && mLocationClient.isStarted()) {
            mLocationClient.stop();
        }
    }

    /**
     * 销毁定位客户端（建议在Application退出时调用）
     */
    public void destroy() {
        stopLocation();
        if (mLocationClient != null) {
            mLocationClient.unRegisterLocationListener(mLocationListener);
            mLocationClient = null;
        }
        mListeners.clear(); // 清除所有回调，避免内存泄漏
    }
}
