package com.nsgk.ruralWeb;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.location.Criteria;
import android.location.LocationManager;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebView;
import android.widget.Toast;

import androidx.core.app.ActivityCompat;

import com.nsgk.ruralWeb.utils.ContextUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class EnvWindowObject
{
    private static final String ID_TAG = EnvWindowObject.class.getName();
    private static final String FUSED_PROVIDER = "fused";

    private final Handler m_handler;
    private final Context m_context;
    private final WebView m_webView;

    // 最近一次获取到的定位坐标, 如果获取定位失败则返回此值. 可能不需要, 因为PASSIVE_PROVIDER就为最近的定位
    private String lastLocation = null;

    public EnvWindowObject(Context context, Handler handler, WebView webView)
    {
        m_context = context;
        m_handler = handler;
        m_webView = webView;
    }

    @JavascriptInterface
    public void Toast(final String message)
    {
        ShowToast(message, Toast.LENGTH_LONG);
    }

    private void ShowToast(final String message, int duration)
    {
        RunOnUIThread(new Runnable() {
            @Override
            public void run()
            {
                Toast.makeText(m_context, message, duration).show();
            }
        });
    }

    @JavascriptInterface
    public void Log(final String message)
    {
        Log.i(ID_TAG, message);
    }

    @JavascriptInterface
    public String GetLocation(final String type)
    {
        try
        {
            if(ActivityCompat.checkSelfPermission(m_context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(m_context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
            {
                Activity activity = (Activity) m_context;

                if (activity.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) && activity.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_COARSE_LOCATION)) // do not ask
                {
                    Toast.makeText(m_context, "请先允许定位服务", Toast.LENGTH_LONG).show();
                    ContextUtils.RequestLocationPermission(activity, FullscreenActivity.PERMISSION_LOCATION_REQUEST_CODE);
                }
                else
                {
                    activity.requestPermissions(new String[] { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION }, FullscreenActivity.PERMISSION_LOCATION_REQUEST_CODE);
                }

                return lastLocation;
            }

            LocationInfo loc;

            loc = GetHighLocation(null);
            if(null == loc)
                loc = GetLastLocation(type);

            if(null != loc)
                lastLocation = loc.longitude + "," + loc.latitude;
            else
                ShowToast("定位失败, 请先开启位置服务", Toast.LENGTH_LONG);
        }
        catch(Throwable e)
        {
            e.printStackTrace();
        }
        return lastLocation;
    }

    @SuppressLint("MissingPermission")
    private LocationInfo GetLastLocation(final String type)
    {
        LocationInfo loc = null;
        try
        {
            LocationManager lm = (LocationManager) m_context.getSystemService(Context.LOCATION_SERVICE);

            List<String> allProviders = lm.getAllProviders();
            Log.i("NSGK", "使用最近所有定位提供器: " + allProviders);
            Map<String, LocationInfo> map = new HashMap<>();
            for(String provider : allProviders)
            {
                Location lastKnownLocation = lm.getLastKnownLocation(provider);
                if(null == lastKnownLocation)
                    continue;
                LocationInfo l = new LocationInfo(provider, lastKnownLocation.getLongitude(), lastKnownLocation.getLatitude());
                map.put(provider, l);
            }

            Log.i("NSGK", "最近定位提供器结果: " + map);
            if(null != type && !type.isEmpty() && map.containsKey(type))
                loc = map.get(type);
            else if(map.containsKey(FUSED_PROVIDER))
                loc = map.get(FUSED_PROVIDER);
            else if(map.containsKey(LocationManager.GPS_PROVIDER))
                loc = map.get(LocationManager.GPS_PROVIDER);
            else if(map.containsKey(LocationManager.NETWORK_PROVIDER))
                loc = map.get(LocationManager.NETWORK_PROVIDER);
            else if(map.containsKey(LocationManager.PASSIVE_PROVIDER))
                loc = map.get(LocationManager.PASSIVE_PROVIDER);
            if(null == loc)
                Log.i("NSGK", "所有提供器无最近定位");
            else
                Log.i("NSGK", "使用提供器最近定位: " + loc.provider);
        }
        catch(Throwable e)
        {
            e.printStackTrace();
        }
        return loc;
    }

    @SuppressLint("MissingPermission")
    private LocationInfo GetHighLocation(String provider)
    {
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
        {
            return null;
        }

        LocationInfo loc = null;
        try
        {
            LocationManager lm = (LocationManager) m_context.getSystemService(Context.LOCATION_SERVICE);

            if(null == provider)
            {
                Criteria criteria = new Criteria();
                criteria.setAccuracy(Criteria.ACCURACY_FINE); // 高精度
//            criteria.setPowerRequirement(Criteria.POWER_HIGH);
//            criteria.setAltitudeRequired(false);
                provider = lm.getBestProvider(criteria, true);
            }
            Log.i("NSGK", "使用高精度定位提供器: " + provider);

            if(null == provider)
            {
                Log.i("NSGK", "无法获取高精度定位提供器");
                return null;
            }

            CompletableFuture<Location> future = new CompletableFuture<>();
            if(null == lastLocation)
                ShowToast("定位中......", Toast.LENGTH_SHORT);
            lm.getCurrentLocation(provider, null, m_context.getMainExecutor(), future::complete);
            Location location = future.get();
            if(null == location)
            {
                Log.i("NSGK", "无法使用高精度提供器定位");
                return null;
            }
            loc = new LocationInfo(provider, location.getLongitude(), location.getLatitude());
            Log.i("NSGK", "使用高精度提供器获取定位: " + loc);
        }
        catch(Throwable e)
        {
            e.printStackTrace();
        }
        return loc;
    }

    protected void RunOnUIThread(Runnable runnable)
    {
        if(null != m_handler)
            m_handler.post(runnable);
        else if(m_context instanceof Activity)
            ((Activity)m_context).runOnUiThread(runnable);
        else
        {
            Log.e(ID_TAG, "无法在UI线程中执行");
        }
    }

    protected void CallJSFunc(final String func, Object...args)
    {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < args.length; i++)
        {
            sb.append("'").append(args[i].toString()).append("'");
            if(i < args.length - 1)
                sb.append(", ");
        }
        final String arg = sb.toString();
        RunOnUIThread(new Runnable() {
            @Override
            public void run()
            {
                String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");";
                Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg));
                m_webView.evaluateJavascript(script, new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        Log.e(ID_TAG, String.format("js函数 %s 返回: %s", func, value));
                    }
                });
            }
        });
    }

    protected void CallJSFunc_beforeAndroid4_4(final String func, Object...args)
    {
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < args.length; i++)
        {
            sb.append("'").append(args[i].toString()).append("'");
            if(i < args.length - 1)
                sb.append(", ");
        }
        final String arg = sb.toString();
        RunOnUIThread(new Runnable() {
            @Override
            public void run() {
                Log.e(ID_TAG, String.format("调用js函数: 函数(%s), 参数(%s)", func, arg));
                String script = "javascript:typeof(" + func + ") == 'function' && " + func + "(" + arg + ");";
                Log.e(ID_TAG, script);
                m_webView.loadUrl(script, null);
            }
        });
    }
}