package com.tomastc.smartwatchclient;

import static com.tomastc.smartwatchclient.SmartwatchClient.STATUS.IDLE;
import static com.tomastc.smartwatchclient.SmartwatchProtocol.COMMAND.PONG;
import static com.tomastc.smartwatchclient.SmartwatchProtocol.COMMAND.RESET_ACK;
import static com.tomastc.smartwatchclient.SmartwatchProtocol.COMMAND.RESET_REQUEST;
import static com.tomastc.smartwatchclient.SmartwatchProtocol.COMMAND.TERM_ACK;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.speech.RecognizerIntent;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextClock;
import android.widget.TextView;
import android.widget.Toast;


import androidx.core.app.ActivityCompat;

import com.tomastc.smartwatchclient.lib.GestureLayoutAction;
import com.tomastc.smartwatchclient.lib.GestureRelativeLayout;
import com.tomastc.smartwatchclient.lib.Settings;
import com.tomastc.smartwatchclient.lib.common.CallbackListener;
import com.tomastc.smartwatchclient.lib.common.FileUtil;
import com.tomastc.smartwatchclient.lib.common.MessageListener;
import com.tomastc.smartwatchclient.lib.common.MyAlertDialog;
import com.tomastc.smartwatchclient.lib.common.Utils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.math.BigInteger;
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import okhttp3.WebSocket;

public class MainActivity extends Activity implements
        CallbackListener, MessageListener {

    public static final int ACCEPT_REQUEST_ACTIVITY = 1000;
    public static final int JOIN_REQUEST_ACTIVITY = 1001;

    private TextView txt_title, txt_main_status, txt_device_id;
    private GestureRelativeLayout gestureRelativeLayout;
    private static int title_click = 0;
    private static boolean silent_mode = false;

    public static DeviceInfoDisplay infoDisplay;
    public static SmartwatchClient smartwatchClient = null;

    public static MainActivity instance = null;
    private  TextClock textClock;

    // Make timer for keep alive
    private static final int interval = 60000; // 60 Seconds
    private static Handler handler = new Handler();
    private static Runnable runnable = new Runnable() {
        public void run() {
            //Toast.makeText(MainActivity.this, "Keep alive...", Toast.LENGTH_SHORT).show();
            if (smartwatchClient != null && smartwatchClient.isConnected()) {
                try {
                    JSONObject j_ext = new JSONObject();
                    j_ext.put("user_id", Settings.getPresettingsObject().getString("user_id"));
                    j_ext.put("dev_id", Settings.getPresettingsObject().getString("dev_id"));
                    j_ext.put("dev_group", Settings.getPresettingsObject().getString("dev_group"));
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    SmartwatchProtocol.COMMAND.PING.toString(),
                                    j_ext
                            )
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                // Silent reconnect
                smartwatchClient.connect();
                silent_mode = true;
            }

            handler.postDelayed(runnable, interval);
        }
    };

    private void init() {
        // load preset
        try {
            if ((new FileUtil(getApplicationContext()))
                    .isExists(Settings.getManagementInfo(),
                            getApplicationContext().getFilesDir().getAbsolutePath())) {
                String str = (new FileUtil(getApplicationContext()))
                        .readFile(Settings.getManagementInfo(),
                                getApplicationContext().getFilesDir().getAbsolutePath());
                Settings.setPresettings(str);

                JSONArray jsonArray = new JSONArray(str);
                JSONObject json = jsonArray.getJSONObject(0);

                txt_main_status.setText(
                        String.format("%s \n Group : %s"
                                , json.getString("user_id")
                                , json.getString("dev_group")
                        ));
                txt_device_id.setText(json.getString("dev_id"));

                // Connect to web socket server
                if (!json.has("url"))
                    throw new JSONException("URL not found!");
                smartwatchClient = SmartwatchClient.getInstance(
                        this
                        , this
                        , getApplicationContext()
                        , json.getString("url"));
            }

        } catch (IOException | JSONException e) {
            Log.e(getString(R.string.tag), e.getMessage());

            new MyAlertDialog(this, "Alert",
                    "Settings may be corrupted. Click OK to reset the gadget.",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int which) {
                            try {
                                new FileUtil(getApplicationContext()).removeFile(Settings.getManagementInfo(),
                                        getApplicationContext().getFilesDir().getAbsolutePath());
                            } catch (Exception e) {

                            } finally {

                                finishAffinity();
                                System.exit(0);
                            }
                        }
                    });


            return;
        }

        // update info bar
        this.infoDisplay = new DeviceInfoDisplay(getApplicationContext(), this);
        this.registerReceiver(this.infoDisplay, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

        // start timer
        handler.postDelayed(runnable, interval);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        instance = this;


        // get an int value from the BigInteger object


        textClock = (TextClock) findViewById(R.id.txt_clock);
        textClock.setFormat24Hour("HH:mm:ss");

        txt_title = findViewById(R.id.txt_main_title);
        txt_main_status = findViewById(R.id.txt_main_status);
        txt_device_id = findViewById(R.id.txt_device_id);

        gestureRelativeLayout = findViewById(R.id.main_view);
        gestureRelativeLayout.setOnAfterTouch(new GestureLayoutAction(){
            @Override
            public void onAfterTouch(int direction) {
                Context context = getApplicationContext();
                Log.d(context.getString(R.string.tag), "Direction: " + direction);
                SmartwatchClient smartwatchClient = SmartwatchClient.getInstance();
                if ((direction & GestureRelativeLayout.Direction.DOWN.getId()) > 0) {
//                    if (smartwatchClient != null && !smartwatchClient.isConnected()) {
                        smartwatchClient.disconnect();
                        Toast.makeText(context,
                                "Reconnecting...",
                                Toast.LENGTH_LONG).show();
                        smartwatchClient.connect();
                        silent_mode = false;
//                    }
                }
            }
        });
        txt_title.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (++title_click == 7) {
                    title_click = 0;

                    Toast.makeText(getApplicationContext(), "Settings mode!", Toast.LENGTH_LONG).show();

                    // call Settings activity
                    Log.d(getString(R.string.tag), "start settings activity");
                    Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
                    startActivity(intent);
                }
            }
        });

        // initial
        init();

    }

    public String getMacAddress() {
        try {
            List<NetworkInterface> networkInterfaceList = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface networkInterface : networkInterfaceList) {
                if (!networkInterface.getName().equalsIgnoreCase("wlan0")) {
                    continue;
                }

                byte[] macAddress = networkInterface.getHardwareAddress();
                if (macAddress == null) {
                    return "";
                }

                StringBuilder result = new StringBuilder();
                for (byte data : macAddress) {
                    Log.d("TESTAA"," data =" + data);
                    String test = String.valueOf(Integer.toHexString(data & 0xFF));
                    test = String.format("%2s",test).replace(' ','0');
                    result.append(test).append(":");
                    Log.d("TESTAA"," result =" + result);
                }

                if (result.length() > 0) {
                    result.deleteCharAt(result.length() - 1);
                }
                return result.toString();
            }
        } catch (Exception ignored) {
        }
        return "02:00:00:00:00:00";
    }

    @Override
    protected void onDestroy() {

        super.onDestroy();

        if (this.infoDisplay != null) {
            this.unregisterReceiver(this.infoDisplay);
        }

        if (smartwatchClient != null) {
            smartwatchClient.disconnect();
        }
    }

    @Override
    public void onFinished(String result) {
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                if (result.startsWith("Error") && !silent_mode) {

                    new MyAlertDialog(MainActivity.this, "Alert",
                            result + ", Please contact leader.",
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    if (!smartwatchClient.isConnected()) {
                                        smartwatchClient.connect();
                                        silent_mode = false;
                                    }

                                }
                            });
                }
                if (infoDisplay != null)
                    infoDisplay.updateIcons();
            }
        });
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {

        Log.d(getString(R.string.tag), String.format("%s : received -> \"%s\"", this.getLocalClassName(),
            text));

        try {
            JSONObject jsonObject = new JSONObject(text);
            JSONObject j_ext;
            Intent intent;

            switch (SmartwatchProtocol.COMMAND.valueOf(jsonObject.getString("cmd"))) {
                case HELLO:
                    j_ext = new JSONObject(jsonObject.getString("ext"));
                    SmartwatchClient.getInstance().client_id = j_ext.getInt("id");

                    j_ext = new JSONObject();
                    j_ext.put("user_id", Settings.getPresettingsObject().getString("user_id"));
                    j_ext.put("dev_id", Settings.getPresettingsObject().getString("dev_id"));
                    j_ext.put("dev_group", Settings.getPresettingsObject().getString("dev_group"));
                    j_ext.put("extra_parms", Settings.getPresettingsObject().getString("ext_parm"));
                    j_ext.put("mac_address", Settings.getPresettingsObject().getString("mac_addr"));
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    SmartwatchProtocol.COMMAND.REGISTER_REQUEST.toString(),
                                    j_ext
                            )
                    );
                    break;

                case REGISTER_ACK:
                    SmartwatchClient.getInstance().status = SmartwatchClient.STATUS.IDLE;
                    break;

                case ACCEPT_REQUEST:

                    SmartwatchClient.getInstance().status = SmartwatchClient.STATUS.ACCEPT_ACK;

                    j_ext = new JSONObject(jsonObject.getString("ext"));
                    j_ext.put("user_id", Settings.getPresettingsObject().getString("user_id"));
                    j_ext.put("dev_id", Settings.getPresettingsObject().getString("dev_id"));
                    j_ext.put("dev_group", Settings.getPresettingsObject().getString("dev_group"));
                    j_ext.put("extra_parms", Settings.getPresettingsObject().getString("ext_parm"));
                    j_ext.put("mac_address", Settings.getPresettingsObject().getString("mac_addr"));
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    SmartwatchProtocol.COMMAND.ACCEPT_YES.toString(),
                                    j_ext
                            )
                    );
                    Utils.vibrate(MainActivity.this, Utils.VIBRATE_PATTERN1);

                    // call Accept request activity
                    Log.d(getString(R.string.tag), "start accept request activity");
                    intent = new Intent(MainActivity.this, AcceptRequestActivity.class);
                    intent.putExtra("ext", jsonObject.getString("ext"));
                    startActivityForResult(intent, ACCEPT_REQUEST_ACTIVITY);
                    break;

//                case JOIN_REQUEST:
//                    SmartwatchClient.getInstance().status = SmartwatchClient.STATUS.JOIN_ACK;
//
//                    j_ext = new JSONObject(jsonObject.getString("ext"));
//                    j_ext.put("user_id", Settings.getPresettingsObject().getString("user_id"));
//                    j_ext.put("dev_id", Settings.getPresettingsObject().getString("dev_id"));
//                    j_ext.put("dev_group", Settings.getPresettingsObject().getString("dev_group"));
//                    SmartwatchClient.getInstance().sendMessage(
//                            SmartwatchProtocol.encapsulation(
//                                    SmartwatchProtocol.COMMAND.JOIN_ACK.toString(),
//                                    j_ext
//                            )
//                    );
//
//                    Utils.vibrate(MainActivity.this, Utils.VIBRATE_PATTERN1);
//
//                    // call Join request activity
//                    Log.d(getString(R.string.tag), "start join request activity");
//                    intent = new Intent(MainActivity.this, JoinRequestActivity.class);
//                    intent.putExtra("ext", jsonObject.getString("ext"));
//                    startActivityForResult(intent, JOIN_REQUEST_ACTIVITY);
//                    break;

                case RESET_REQUEST:
                    SmartwatchClient.getInstance().status = SmartwatchClient.STATUS.IDLE;
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    RESET_ACK.toString(),
                                    null
                            )
                    );
                    break;

                case PING:
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    PONG.toString(),
                                    null
                            )
                    );
                    break;

                case TERM_REQUEST:
                    SmartwatchClient.getInstance().status = SmartwatchClient.STATUS.IDLE;
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    TERM_ACK.toString(),
                                    null
                            )
                    );
                    break;
            }
        } catch (JSONException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        // update MessageListener class
        SmartwatchClient client = SmartwatchClient.getInstance();
        if (client != null) {
            //Log.d(getString(R.string.tag), "onResume() on class " + getLocalClassName());
            client.setOnMessageListener(this);


            // Tell server ready to receive new job
            // Reset client to IDLE state
            if (SmartwatchClient.getInstance().status != IDLE) {
                SmartwatchClient.getInstance().status = IDLE;
                try {
                    JSONObject j_ext = new JSONObject();
                    j_ext.put("user_id", Settings.getPresettingsObject().getString("user_id"));
                    j_ext.put("dev_id", Settings.getPresettingsObject().getString("dev_id"));
                    j_ext.put("dev_group", Settings.getPresettingsObject().getString("dev_group"));
                    j_ext.put("extra_parms", Settings.getPresettingsObject().getString("ext_parm"));
                    j_ext.put("mac_address", Settings.getPresettingsObject().getString("mac_addr"));
                    SmartwatchClient.getInstance().sendMessage(
                            SmartwatchProtocol.encapsulation(
                                    RESET_REQUEST.toString(),
                                    j_ext
                            )
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch(requestCode) {
            case (ACCEPT_REQUEST_ACTIVITY) :
            case (JOIN_REQUEST_ACTIVITY) :{
                if (resultCode == Activity.RESULT_OK) {
                    // TODO Extract the data returned from the child Activity.
                    String text = data.getStringExtra("last_message");
                    Log.d(getString(R.string.tag), String.format("called intent return message : %s", text));
                    this.onMessage(null, text);
                }
                break;
            }
        }
    }
}