package com.xplora.xpsettings.Activity;

import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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 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;
    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 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;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list);
        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 (data == null)
            return;
        switch (requestCode) {
            case REQUEST_LOGIN:
                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")) &&
                            model.BSSID.equals(data.getStringExtra("bssid"))) {
                        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) {
                    @SuppressLint("MissingPermission") List<WifiConfiguration> savedList = wifiManager.getConfiguredNetworks();
                    for (WifiConfiguration ap : savedList) {
                        String ssid = ap.SSID;
                        if (ssid.substring(1, ssid.length() - 1).equals(wifiModel.title) && ap.BSSID.equals(wifiModel.BSSID)) {
                            connect(ap);
                            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) {
        mDataList.clear();
        isOn = init ? wifiManager.isWifiEnabled() : isOn;
        //switch
        WifiModel switchModel = new WifiModel();
        switchModel.title = getResources().getStringArray(R.array.settings_title_array)[0];
        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.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();
            }
            connectedModel.title = ssid;
            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 (bssid == null || (connected != null && bssid.equals(connected.getBSSID()))) {
                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));
                savedModel.status = WifiModel.STATUS.CONNECTING;
            } else {
                savedModel.status = WifiModel.STATUS.SAVED;
            }
            savedModel.BSSID = bssid;
            mDataList.add(savedModel);
            savedList.add(bssid);
        }

        if (list != null && !list.isEmpty()) {
            for (ScanResult result : list) {
                if (connected != null && connected.getBSSID().equals(result.BSSID)) {
                    continue;
                }
                if (!savedList.isEmpty() && savedList.contains(result.BSSID)) {
                    continue;
                }
                WifiModel wifiModel = new WifiModel();
                String ssid = result.SSID;
                if (ssid.trim().isEmpty() || ssid.contains("<unknown ssid>")) {
                    ssid = result.BSSID;
                }
                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.getBSSID().equals(result.BSSID)) {
                    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("wifitest", "added : " + wifiModel.title + "[" + wifiModel.BSSID + ";" + wifiModel.status + "]");
        }
    }

    @SuppressLint("MissingPermission")
    private void initView() {
        //标题
        setWatchTitle(getResources().getStringArray(R.array.settings_title_array)[0]);

        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 != 0) {
                Intent intent = new Intent(WiFiActivity.this, WifiLoginActivity.class);
                intent.putExtra("ssid", model.title);
                intent.putExtra("bssid", model.BSSID);
                startActivityForResult(intent, REQUEST_LOGIN);

//                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, WiFiControlActivity.class);
//                    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("wifitest", "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);
    }

    @SuppressLint("MissingPermission")
    private void connect(WifiConfiguration configuration) {
        int id;
        if (wifiManager.getConfiguredNetworks().contains(configuration)) {
            id = configuration.networkId;
        } else {
            id = wifiManager.addNetwork(configuration);
        }
        Log.d("wifitest", "add network : " + configuration.SSID + ", id : " + id);
        if (id == -1) return;

        for (WifiModel wifiModel : mDataList) {
            if (wifiModel.status == WifiModel.STATUS.CONNECTED) {
                wifiModel.status = WifiModel.STATUS.SAVED;
            }
            if (configuration.SSID.equals("\"" + wifiModel.title + "\"")) {
                Log.d("wifitest", "found ssid");
                wifiModel.status = WifiModel.STATUS.CONNECTING;
            }
        }
        if (adapter != null) {
            adapter.notifyDataSetChanged();
        }
        Log.d("wifitest", "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();
        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)) && model.BSSID.equals(configuration.BSSID)) {
                wifiManager.enableNetwork(configuration.networkId, false);
                break;
            }
        }
        updateList();
    }

    @SuppressLint("MissingPermission")
    private void forget(WifiModel model) {
        for (WifiConfiguration configuration : wifiManager.getConfiguredNetworks()) {
            String ssid = configuration.SSID;
            if (model.title.equals(ssid.substring(1, ssid.length() - 1)) && model.BSSID.equals(configuration.BSSID)) {
                wifiManager.removeNetwork(configuration.networkId);
                break;
            }
        }
        updateList();
    }

    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_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;
                default:
                    break;
            }

        }
    };

    private class ConnectionReceiver extends android.content.BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("wifitest", "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) {
            if (!WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) {
                return;
            }
            WifiInfo info = wifiManager.getConnectionInfo();
            if (info.getNetworkId() == connecting && info.getSupplicantState() == SupplicantState.COMPLETED) {
                connecting = -1;
                handler.removeMessages(MSG_CONNECT_TIMEOUT);
                updateList();
            }
        }

    }
}