package com.xplora.xpsettings.Activity;

import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.SupplicantState;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.ListView;

import com.xplora.xpsettings.Adapter.WiFiAdapter;
import com.xplora.xpsettings.Model.WifiModel;
import com.xplora.xpsettings.R;
import com.xplora.xpsettings.Utils.Constant;
import com.xplora.xpsettings.Utils.ResUtils;

import java.util.ArrayList;
import java.util.List;


public class WiFiActivity extends BaseActivity {
    private final List<WifiModel> mDataList = new ArrayList<>();
    private WifiManager wifiManager;
    List<ScanResult> list;
    ListView listView;
    WiFiAdapter adapter;
    ConnectionReceiver scanResultReceiver = null;
    WiFiConnectReceiver wiFiConnectReceiver = null;
    boolean isOn = false;
    int connecting = -1;

    public static final int MSG_SWITCH_CHANGE = 0;
    public static final int MSG_REFRESH_CLICK = 10;
    private static final int MSG_SCAN_RESULT_UPDATE = 1;
    private static final int MSG_START_SCAN_DELAY = 2;
    private static final int MSG_CONNECT_TIMEOUT = 3;
    private static final int MSG_CONNECTED = 4;

    private static final int REQUEST_LOGIN = 0;
    private static final int REQUEST_CONTROL = 1;

    static final int OPERATE_FORGET = 0;
    static final int OPERATE_DISCONNECT = 1;
    static final int OPERATE_CONNECT = 2;

    private SharedPreferences mSharedPreferences;
    private String mSsid = "";
    private boolean showFailToast = true;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
        mSharedPreferences= getSharedPreferences("newWork", MODE_PRIVATE);
        initWiFi();
        initData(true);
        initView();
    }

    @Override
    protected void onResume() {
        super.onResume();
        initData(true);
        adapter.notifyDataSetChanged();
        initScan();
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != -1)
            return;
		if (data == null)
            return;
        switch (requestCode) {
            case REQUEST_LOGIN:
                mSsid = data.getStringExtra("ssid");
                showFailToast = true;
                connect(data.getStringExtra("ssid"),
                        data.getStringExtra("bssid"),
                        data.getStringExtra("password"));
                break;
            case REQUEST_CONTROL:
                int operation = data.getIntExtra("operation", -1);
                WifiModel wifiModel = null;
                for (WifiModel model : mDataList) {
                    if (model.title.equals(data.getStringExtra("ssid"))) {
                        wifiModel = model;
                        break;
                    }
                }
                if (wifiModel == null) return;
                if (operation == OPERATE_FORGET) {
                    forget(wifiModel);
                } else if (operation == OPERATE_DISCONNECT) {
                    disConnect(wifiModel);
                } else if (operation == OPERATE_CONNECT) {
                    wifiModel.status = WifiModel.STATUS.CONNECTING;
                    @SuppressLint("MissingPermission")
                    List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
                    for (WifiConfiguration ap : list) {
                        String ssid = ap.SSID;
                        if (ssid.substring(1, ssid.length() - 1).equals(wifiModel.title)) {
                            connect(ap, true);
                            break;
                        }
                    }
                }
                break;
            default:
                break;
        }
    }

    @SuppressLint("WifiManagerLeak")
    private void initWiFi() {
        wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    }

    private void initScan() {
        if (!wifiManager.isWifiEnabled()) {
            handler.sendEmptyMessageDelayed(MSG_START_SCAN_DELAY, 100);
            return;
        }
        startScan();
    }

    @SuppressLint("MissingPermission")
    private void initData(boolean init) {
        String[] array = ResUtils.getStringArray("connections_title_array_", 4);
        mDataList.clear();
        isOn = init ? wifiManager.isWifiEnabled() : isOn;
        //switch
        WifiModel switchModel = new WifiModel();
        switchModel.title = array[1];
        switchModel.isShowArrow = true;
        switchModel.isOn = isOn;
        switchModel.value = "";
        switchModel.status = WifiModel.STATUS.NA;
        switchModel.cellType = Constant.CellType.SWITCH;
        mDataList.add(switchModel);

/*        WifiModel test = new WifiModel();
        test.title = "test";
        test.isShowArrow = true;
        test.isOn = isOn;
        test.value = "";
        test.status = WifiModel.STATUS.LOCKED;
        mDataList.add(test);*/
        if (!isOn) return;

        WifiModel refreshModel = new WifiModel();
        refreshModel.title = getResources().getString(R.string.networks);
        refreshModel.cellType = Constant.CellType.REFRESH;
        mDataList.add(refreshModel);

        NetworkInfo.State state = null;
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        Network[] networks = connectivityManager.getAllNetworks();
        for (Network network : networks) {
            NetworkInfo info = connectivityManager.getNetworkInfo(network);
            if (info != null && info.getType() == ConnectivityManager.TYPE_WIFI) {
                state = info.getState();
            }
        }

        WifiInfo connected = null;
        if (state != null && state.equals(NetworkInfo.State.CONNECTED)) {
            connected = wifiManager.getConnectionInfo();
            WifiModel connectedModel = new WifiModel();
            String ssid = connected.getSSID();
            if (ssid.trim().isEmpty() || ssid.contains("<unknown ssid>")) {
                ssid = connected.getBSSID();
            }

            if(ssid == null || ssid.isEmpty())
                connectedModel.title = "";
            else
                connectedModel.title = ssid.replace("\"", "");
            connectedModel.isShowArrow = true;
            connectedModel.isOn = isOn;
            connectedModel.value = "";
            connectedModel.status = WifiModel.STATUS.CONNECTED;
            connectedModel.BSSID = connected.getBSSID();
            mDataList.add(connectedModel);
        }

        List<WifiConfiguration> savedAp = wifiManager.getConfiguredNetworks();
        List<String> savedList = new ArrayList<>();
        for (int i = 0; i < savedAp.size(); i++) {
            WifiConfiguration wifiConfiguration = savedAp.get(i);
            String bssid = wifiConfiguration.BSSID;
            String ssid = wifiConfiguration.SSID;
            if (ssid.trim().isEmpty() || ssid.contains("<unknown ssid>")) {
                continue;
            }

            if (connected != null && ssid.equals(connected.getSSID())) {
                continue;
            }

            WifiModel savedModel = new WifiModel();
            savedModel.title = ssid.substring(1, ssid.length() - 1);
            savedModel.isShowArrow = true;
            savedModel.isOn = isOn;
            savedModel.value = "";
            if (connected == null && i == 0 && connecting == -1) {
            connect(savedAp.get(i),false);
                savedModel.status = WifiModel.STATUS.CONNECTING;
            } else {
                savedModel.status = WifiModel.STATUS.SAVED;
            }
            savedModel.BSSID = bssid;
            mDataList.add(savedModel);
            savedList.add(ssid);
        }

        if (list != null && !list.isEmpty()) {
            for (ScanResult result : list) {
                if (connected != null && connected.getSSID() != null && connected.getSSID().equals(result.SSID)) {
                    continue;
                }
                if (!savedList.isEmpty() && savedList.contains(result.SSID)) {
                    continue;
                }
                if (!is24GHzWifi(result.frequency)) {
                    continue;
                }
                WifiModel wifiModel = new WifiModel();
                String ssid = result.SSID;
                if (ssid.trim().isEmpty() || ssid.contains("<unknown ssid>")) {
                    continue;
                }
                wifiModel.title = ssid;
                wifiModel.isShowArrow = true;
                wifiModel.isOn = isOn;
                wifiModel.value = "";
                wifiModel.status = WifiModel.STATUS.NA;
                wifiModel.BSSID = result.BSSID;
                String capabilities = result.capabilities.trim();
                if (connected != null && connected.getSSID().equals(result.SSID)) {
                    wifiModel.status = WifiModel.STATUS.CONNECTED;
                } else if (capabilities.isEmpty() || capabilities.equals("[ESS]")) {
                    wifiModel.status = WifiModel.STATUS.OPEN;
                	wifiModel.isShowArrow = false;
                } else {
                    wifiModel.status = WifiModel.STATUS.LOCKED;
                }
                mDataList.add(wifiModel);
            }
        }
        for (WifiModel wifiModel : mDataList) {
            Log.d(TAG, "added : " + wifiModel.title + "[" + wifiModel.BSSID + ";" + wifiModel.status + "]");
        }
    }

    @SuppressLint("MissingPermission")
    private void initView() {
        adapter = new WiFiAdapter(WiFiActivity.this, 0, mDataList, handler);
        listView = findViewById(R.id.activity_listview);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener((adapterView, view, i, l) -> {
            WifiModel model = (WifiModel) adapterView.getAdapter().getItem(i);
            if (i > 1) {
                if (model.status == WifiModel.STATUS.LOCKED) {
                    Intent intent = new Intent(WiFiActivity.this, WifiLoginActivity.class);
                    intent.putExtra("ssid", model.title);
                    intent.putExtra("bssid", model.BSSID);
                    startActivityForResult(intent, REQUEST_LOGIN);
                } else if (model.status == WifiModel.STATUS.OPEN) {
                    connect(model.title, model.BSSID, "");
            } else if (model.status == WifiModel.STATUS.SAVED || model.status == WifiModel.STATUS.CONNECTED) {
                    Intent intent = new Intent(WiFiActivity.this, ConnectionsControlActivity.class);
                    intent.putExtra("view_type", 1);
                    intent.putExtra("ssid", model.title);
                    intent.putExtra("bssid", model.BSSID);
                    intent.putExtra("status", model.status.ordinal());
                    startActivityForResult(intent, REQUEST_CONTROL);
                }
            }
        });
    }

    void changeWiFiStatus() {
        wifiManager.setWifiEnabled(isOn);
        if (isOn) {
            initScan();
        }
        list = null;
        updateList();
    }

    private void updateList() {
        initData(false);
        adapter.notifyDataSetChanged();
    }

    private void startScan() {
        if (wifiManager != null) {
            registerReceiver();
            wifiManager.startScan();
        }
    }

    private void connect(String ssid, String bssid, String password) {
        Log.d(TAG, "try connect : " + ssid + "; " + bssid);
        WifiConfiguration configuration = new WifiConfiguration();

        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
        configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
        configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
        configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
        configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
        configuration.allowedProtocols.set(WifiConfiguration.Protocol.WPA);

        if (password.isEmpty()) {
            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            configuration.allowedAuthAlgorithms.clear();
        } else {
            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
        }
        configuration.status = WifiConfiguration.Status.ENABLED;

        configuration.SSID = String.format("\"%s\"", ssid);
        configuration.BSSID = bssid;
        if (!password.isEmpty()) {
            configuration.preSharedKey = String.format("\"%s\"", password);
        }
        connect(configuration,false);
    }

    @SuppressLint("MissingPermission")
    private void connect(WifiConfiguration configuration,boolean clearId) {
        Log.d(TAG, "connect: configuration.SSID:" + configuration.SSID);

        int id;
        if (wifiManager.getConfiguredNetworks().contains(configuration)) {
            id = configuration.networkId;
        } else {
            id = wifiManager.addNetwork(configuration);
        }
        Log.d(TAG, "connect : " + configuration.SSID + ", id : " + id);
        if (id == -1) return;

        for (WifiModel wifiModel : mDataList) {
            Log.d(TAG, "connect: status :" + wifiModel.status + " title:" + wifiModel.title);
            if (wifiModel.status == WifiModel.STATUS.CONNECTED) {
                wifiModel.status = WifiModel.STATUS.SAVED;
            }
            if (configuration.SSID.equals("\"" + wifiModel.title + "\"")) {
                Log.d(TAG, "connect: " + "found ssid");
                wifiModel.status = WifiModel.STATUS.CONNECTING;
            }
        }
        if (adapter != null) {
            adapter.notifyDataSetChanged();
        }
        Log.d(TAG, "per-enable : " + configuration.preSharedKey);
        if (scanResultReceiver == null) {
            IntentFilter filter = new IntentFilter();
            filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
            wiFiConnectReceiver = new WiFiConnectReceiver();
            registerReceiver(wiFiConnectReceiver, filter);
        }
        wifiManager.disconnect();
        if(clearId){
            removeNetWorkId(id);
        }
        if(!netWorkIdIsSave(id))
            wifiManager.enableNetwork(id, true);
        connecting = id;
        handler.sendEmptyMessageDelayed(MSG_CONNECT_TIMEOUT, 60 * 1000);
    }

    @SuppressLint("MissingPermission")
    private void disConnect(WifiModel model) {
        for (WifiConfiguration configuration : wifiManager.getConfiguredNetworks()) {
            String ssid = configuration.SSID;
            if (model.title.equals(ssid.substring(1, ssid.length() - 1))) {
           // wifiManager.enableNetwork(configuration.networkId, false);
            boolean isDisable = wifiManager.disableNetwork (configuration.networkId);
            if(isDisable)
                saveNetWorkId(configuration.networkId);
                break;
            }
        }
        updateList();
    }

    private void saveNetWorkId(int id){
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        int netWorkSize = mSharedPreferences.getInt("networksize", 0);
        if(netWorkSize == 0 ){
            edit.putInt("networkid" + 0, id);
            edit.putInt("networksize" , 1);
            edit.commit();
        }
        for(int i=0;i<netWorkSize; i++) {
            if (mSharedPreferences.getInt("networkid" + i, 0) == id) {
                return;
            } else{
                edit.putInt("networkid" + i, id);
                edit.putInt("networksize" , netWorkSize + 1);
                edit.commit();
            }
        }
    }

    private boolean netWorkIdIsSave(int id){
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        int netWorkSize = mSharedPreferences.getInt("networksize", 0);
        for(int i=0;i<netWorkSize; i++) {
            if (mSharedPreferences.getInt("networkid" + i, 0) == id) {
                return true;
            }
        }
        return false;
    }

    private void removeNetWorkId(int id){
        SharedPreferences.Editor edit = mSharedPreferences.edit();
        int netWorkSize = mSharedPreferences.getInt("networksize", 0);
        for(int i = 0; i < netWorkSize; i++) {
            if (mSharedPreferences.getInt("networkid" + i, 0) == id) {
                edit.putInt("networksize", netWorkSize -1);
                edit.remove("networkid" + i );
                edit.commit();
            }
        }
    }

    @SuppressLint("MissingPermission")
    private void forget(WifiModel model) {
        Log.d(TAG, "forget: " + model.title);
        for (WifiConfiguration configuration : wifiManager.getConfiguredNetworks()) {
            String ssid = configuration.SSID;
            if (model.title.equals(ssid.substring(1, ssid.length() - 1))) {
                boolean isOk = wifiManager.removeNetwork(configuration.networkId);
                Log.d(TAG, "forget result:" + isOk);
                removeNetWorkId(configuration.networkId);
                break;
            }
        }
        updateList();
    }

    private WifiModel getWifiModel(String ssid) {
        for (WifiModel model : mDataList) {
            if (model.title.equals(ssid)) {
                return model;
            }
        }
        return null;
    }

    public static boolean is24GHzWifi(int frequency){
        return frequency > 2400 && frequency < 2500;
    }

    private void registerReceiver() {
        if (scanResultReceiver != null) return;
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        filter.addAction(CONNECTIVITY_ACTION);
        scanResultReceiver = new ConnectionReceiver();
        registerReceiver(scanResultReceiver, filter);
    }

    private void unregisterReceiver() {
        if (scanResultReceiver != null) {
            unregisterReceiver(scanResultReceiver);
            scanResultReceiver = null;
        }
        if (wiFiConnectReceiver != null) {
            unregisterReceiver(wiFiConnectReceiver);
            wiFiConnectReceiver = null;
        }
    }

    Handler handler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_SWITCH_CHANGE:
                    isOn = (int) msg.obj == 1;
                    changeWiFiStatus();
                    break;
                case MSG_REFRESH_CLICK:
                    initScan();
                    break;
                case MSG_SCAN_RESULT_UPDATE:
                    if (wifiManager != null) {
                        list = wifiManager.getScanResults();
                        updateList();
                        break;
                    }
                case MSG_START_SCAN_DELAY:
                    initScan();
                    break;
                case MSG_CONNECT_TIMEOUT:
                    connecting = -1;
                    updateList();
                    break;
                case MSG_CONNECTED:
                    boolean needResult = getIntent().getBooleanExtra("needResult", false);
                    if(needResult) {
                        setResult(RESULT_OK);
                        finish();
                    }
                    break;
                default:
                    break;
            }

        }
    };

    private class ConnectionReceiver extends android.content.BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "ConnectionReceiver, onReceive : " + intent.getAction());
            if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) && intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)) {
                handler.sendEmptyMessage(MSG_SCAN_RESULT_UPDATE);
            } else if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
                NetworkInfo info = intent
                        .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
                if (info != null && NetworkInfo.State.CONNECTED == info.getState()
                        && info.isAvailable() && info.getType() == ConnectivityManager.TYPE_WIFI) {
                    updateList();
                }
            }
        }
    }

    private class WiFiConnectReceiver extends android.content.BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "WiFiConnectReceiver onReceive: ");
            if (!WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) {
                return;
            }
            WifiInfo info = wifiManager.getConnectionInfo();
            String wifiId = info != null ? info.getSSID() : null;
            Log.d(TAG, "WiFiConnectReceiver wifiId: " + wifiId);
            if(info.getSupplicantState() == SupplicantState.DISCONNECTED){
                Log.d(TAG, "WiFiConnectReceiver onReceive: State DISCONNECTED");
                 if(wifiId!=null && !"".equals(wifiId) && wifiId.equals("\""+mSsid+"\"") && showFailToast){
                     toast(getString(R.string.password_wrong));
                     showFailToast = false;
                     WifiModel model = getWifiModel(mSsid);
                     if (model != null) {
                         forget(model);
                     }
                 }
            }
            if (info.getNetworkId() == connecting && info.getSupplicantState() == SupplicantState.COMPLETED) {
                connecting = -1;
                handler.removeMessages(MSG_CONNECT_TIMEOUT);
                //updateList();
                adapter.notifyDataSetChanged();
                handler.sendEmptyMessage(MSG_CONNECTED);
            }

            if(wifiId!=null && wifiId.equals("\""+mSsid+"\"")){
                Log.d(TAG, "onReceive: clear");
               //mSsid = "";
            }
        }
    }
}