package com.shareable;

import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import android.util.Patterns;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;

import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import info.whitebyte.hotspotmanager.OreoHotspotStatus;
import info.whitebyte.hotspotmanager.WifiApManager;

public class ShareableHotspot {
    private WifiApManager wifi;
    private WifiConfiguration oldconfig;
    private ReactApplicationContext mContext;
    public static List<String> DSLITE_LIST = Arrays.asList("192.0.0.0","192.0.0.1","192.0.0.2","192.0.0.3","192.0.0.4","192.0.0.5","192.0.0.6","192.0.0.7");
    private IntentFilter hotspotFilter;
    private HotspotStates states;

    public ShareableHotspot(ReactApplicationContext context) {
        wifi = new WifiApManager(context);
        mContext = context;
    }


    public void onDestroy() {
        if(states != null && isEnabled()) {
            mContext.unregisterReceiver(states);
        }

    }

    public void setPermissions() {
        wifi.showWritePermissionSettings(false);
    }

    public boolean isEnabled() {
        return wifi.isWifiApEnabled();
    }

    public void enable(ReadableMap info, Promise enable) {

        states = new HotspotStates(enable, null);
        hotspotFilter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");

        mContext.registerReceiver(states, hotspotFilter);

        WifiConfiguration config = wifi.getWifiApConfiguration();
        oldconfig = wifi.getWifiApConfiguration();


        config.SSID = info.getString("ssid");
        config.preSharedKey = info.getString("password");
        config.hiddenSSID = info.getBoolean("hidden");


        if(!wifi.setWifiApEnabled(config, true))
            enable.reject("Error", "Unable to open hotspot");
    }


    public void restart(ReadableMap info, final Promise promise) {
        new hotspotRestart(info, promise).execute();
    }


    public void disable(Promise disable) {

        wifi.setWifiApConfiguration(oldconfig);

        states = new HotspotStates(null, disable);
        mContext.registerReceiver(states, hotspotFilter);


        if(!wifi.setWifiApEnabled(null, false))
            disable.reject("Error", "Unable to close hotspot");

    }

    private String getIPAddress() {
        String ipAddress = "error";
        String tmp = "0.0.0.0";

        for (InterfaceAddress address : getInetAddresses()) {
            if (!address.getAddress().isLoopbackAddress()) {
                tmp = address.getAddress().getHostAddress();
                if (!inDSLITERange(tmp)) {
                    ipAddress = tmp;
                }
            }
        }

        return ipAddress;
    }


    private List<InterfaceAddress> getInetAddresses() {
        List<InterfaceAddress> addresses = new ArrayList<>();
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface intf = en.nextElement();

                for (InterfaceAddress interface_address : intf.getInterfaceAddresses()) {
                    addresses.add(interface_address);
                }
            }
        } catch (Exception ex) {
            Log.e("error", ex.toString());
        }
        return addresses;
    }

    private Boolean inDSLITERange (String ip) {
        // Fixes issue https://github.com/pusherman/react-native-network-info/issues/43
        // Based on comment https://github.com/pusherman/react-native-network-info/issues/43#issuecomment-358360692
        // added this check in getIPAddress and getIPV4Address
        return ShareableHotspot.DSLITE_LIST.contains(ip);
    }

    class HotspotStates extends BroadcastReceiver {
        private Promise enable;
        private Promise disable;

        public HotspotStates(Promise enable, Promise disable) {
            this.enable = enable;
            this.disable = disable;
        }
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if ("android.net.wifi.WIFI_AP_STATE_CHANGED".equals(action)) {
                final int hotspotState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
                // get Wi-Fi Hotspot state here
                switch(hotspotState) {
                    case 13:
                        if(this.enable != null) {
                            String ip = getIPAddress();
                            Boolean ipAssigned = Patterns.IP_ADDRESS.matcher(ip).matches();

                            while(!ipAssigned) {
                                ip = getIPAddress();
                                ipAssigned = Patterns.IP_ADDRESS.matcher(ip).matches();
                            }

                            context.unregisterReceiver(states);
                            enable.resolve(ip);


                        }

                        break;
                    case 11:
                        /*if (mState != STATE_ENABLING && mState != STATE_RESTARTING) {
                            if(mPromise != null) {
                                mState = STATE_NONE;
                                mPromise.resolve(null);
                                context.unregisterReceiver(mReceiver);
                            }
                            else {
                                // user turned off hotspot from device itself
                            }
                        } else if(mState == STATE_RESTARTING) {
                            mState = STATE_NONE;
                        }*/
                        if(this.disable != null) {
                            context.unregisterReceiver(states);
                            disable.resolve("Hotspot disabled");
                        }
                        break;
                    case 14:
                        if(this.enable != null)
                            enable.reject("Error", "Failed opening hotspot");
                        else
                            disable.reject("Error", "Failed closing hotspot");
                        context.unregisterReceiver(states);
                        break;
                }

            }
        }
    }

    private class hotspotRestart extends AsyncTask<Void, Void, Boolean> {
        private Promise promise;
        private ReadableMap info;
        public hotspotRestart( ReadableMap info ,Promise promise) {
            this.info = info;
            this.promise = promise;
        }
        @Override
        protected Boolean doInBackground(Void... voids) {

            //mState = STATE_RESTARTING;


            if(wifi.setWifiApEnabled(null, false))
                return true;

            //while(wifi.isWifiApEnabled() != true);

            // hotspot has been disabled do my configuration
            return false;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if(result)
                enable(this.info, this.promise);
        }
    }
}
