package com.fastvpnapp;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.VpnService;
import android.os.Bundle;
import android.os.RemoteException;
import android.view.View;
import android.widget.TextView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.airbnb.lottie.LottieAnimationView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import de.blinkt.openvpn.OpenVpnApi;
import de.blinkt.openvpn.core.OpenVPNService;
import de.blinkt.openvpn.core.OpenVPNThread;
import de.blinkt.openvpn.core.VpnStatus;

public class MainActivity extends AppCompatActivity {

    private boolean vpnStart = false;
    private LottieAnimationView lottieAnimationView;
    private CheckInternetConnection connection;
    private TextView vpnBtn,durationTv,lastPacketReceiveTv,byteInTv,byteOutTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lottieAnimationView = findViewById(R.id.connect);
        vpnBtn = findViewById(R.id.vpnBtn);
        durationTv = findViewById(R.id.durationTv);
        byteInTv = findViewById(R.id.byteInTv);
        byteOutTv = findViewById(R.id.byteOutTv);
        lastPacketReceiveTv = findViewById(R.id.lastPacketReceiveTv);
        vpnBtn.setOnClickListener(view -> {
            if (vpnStart) {
                findViewById(R.id.wifi).setVisibility(View.GONE);
                lottieAnimationView.pauseAnimation();
                confirmDisconnect();
            } else {
                findViewById(R.id.wifi).setVisibility(View.GONE);
                lottieAnimationView.playAnimation();
                prepareVpn();
            }
        });
        findViewById(R.id.server).setOnClickListener(view -> startActivity(new Intent(this,ServerActivity.class)));
        updateCurrentServerIcon();
        connection = new CheckInternetConnection();
        isServiceRunning();
        VpnStatus.initLogCache(getCacheDir());
        RecyclerView sidebar = findViewById(R.id.sidebar);
        DrawerLayout drawerLayout = findViewById(R.id.drawer);
        sidebar.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        sidebar.setHasFixedSize(false);sidebar.setAdapter(new SidebarAdapter(this,drawerLayout));
        findViewById(R.id.menu).setOnClickListener(view -> drawerLayout.openDrawer(GravityCompat.START));
    }

    public void confirmDisconnect(){
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(getString(R.string.connection_close_confirm));
        builder.setPositiveButton(getString(R.string.yes), (dialog, id) -> stopVpn());
        builder.setNegativeButton(getString(R.string.no), (dialog, id) -> dialog.dismiss());
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    private void prepareVpn() {
        if (!vpnStart) {
            if (getInternetStatus()) {
                Intent intent = VpnService.prepare(this);
                if (intent != null) {
                    vpnLauncher.launch(intent);
                } else {
                    startVpn();
                }
                status("connecting");
            } else {
                lottieAnimationView.pauseAnimation();
                Utils.showToast(this,"you have no internet connection !!");
            }
        } else if (stopVpn()) {
            lottieAnimationView.pauseAnimation();
            Utils.showToast(this,"Disconnect Successfully");
        }
    }


    public boolean stopVpn() {
        try {
            OpenVPNThread.stop();
            status("connect");
            vpnStart = false;
            lottieAnimationView.pauseAnimation();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    ActivityResultLauncher<Intent> vpnLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    startVpn();
                } else {
                    lottieAnimationView.pauseAnimation();
                    Utils.showToast(MainActivity.this,"Permission Deny !!");
                }
            });

    public boolean getInternetStatus() {
        return connection.netCheck(this);
    }


    public void isServiceRunning() {
        setStatus(OpenVPNService.getStatus());
    }

    private void startVpn() {
        try {
            InputStream conf = getAssets().open(Utils.server.getOvpn());
            InputStreamReader isr = new InputStreamReader(conf);
            BufferedReader br = new BufferedReader(isr);
            StringBuilder config = new StringBuilder();
            String line;
            while (true) {
                line = br.readLine();
                if (line == null) break;
                config.append(line).append("\n");
            }
            br.readLine();
            OpenVpnApi.startVpn(this, config.toString(),Utils.server.getCountry(),Utils.server.getOvpnUserName(),Utils.server.getOvpnUserPassword());
            vpnStart = true;
        } catch (IOException | RemoteException e) {
            lottieAnimationView.pauseAnimation();
            e.printStackTrace();
        }
    }

    public void setStatus(String connectionState) {
        if (connectionState!= null)
            switch (connectionState) {
                case "DISCONNECTED":
                    status("connect");
                    vpnStart = false;
                    lottieAnimationView.pauseAnimation();
                    OpenVPNService.setDefaultStatus();
                    break;
                case "CONNECTED":
                    vpnStart = true;
                    status("connected");
                    lottieAnimationView.pauseAnimation();
                    findViewById(R.id.wifi).setVisibility(View.VISIBLE);
                    break;
                case "WAIT":
                    break;
                case "AUTH":
                    break;
                case "RECONNECTING":
                    status("connecting");
                    break;
                case "NONETWORK":
                    lottieAnimationView.pauseAnimation();
                    break;
            }

    }

    @SuppressLint("SetTextI18n")
    public void status(String status) {
        switch (status) {
            case "connect":
                vpnBtn.setText(getString(R.string.connect));
                break;
            case "connecting":
                vpnBtn.setText(getString(R.string.connecting));
                break;
            case "connected":
                vpnBtn.setText(getString(R.string.disconnect));
                break;
            case "tryDifferentServer":
                vpnBtn.setText("Try Different Server");
                break;
            case "loading":
                vpnBtn.setText("Loading Server..");
                break;
            case "invalidDevice":
                vpnBtn.setText("Invalid Device");
                break;
            case "authenticationCheck":
                vpnBtn.setText("Authentication Checking...");
                break;
        }
    }

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                setStatus(intent.getStringExtra("state"));
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                String duration = intent.getStringExtra("duration");
                String lastPacketReceive = intent.getStringExtra("lastPacketReceive");
                String byteIn = intent.getStringExtra("byteIn");
                String byteOut = intent.getStringExtra("byteOut");
                if (duration == null) duration = "00:00:00";
                if (lastPacketReceive == null) lastPacketReceive = "0";
                if (byteIn == null) byteIn = " ";
                if (byteOut == null) byteOut = " ";
                updateConnectionStatus(duration, lastPacketReceive, byteIn, byteOut);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };


    @SuppressLint("SetTextI18n")
    public void updateConnectionStatus(String duration, String lastPacketReceive, String byteIn, String byteOut) {
        durationTv.setText("Duration: " + duration);
        lastPacketReceiveTv.setText("Packet Received: " + lastPacketReceive + " second ago");
        byteInTv.setText("Bytes In: " + byteIn);
        byteOutTv.setText("Bytes Out: " + byteOut);
    }

    @SuppressLint("SetTextI18n")
    public void updateCurrentServerIcon() {
        if(Utils.server != null) {
            if(Utils.server.getCountry().equals("Auto Select the Best Server")) {
                ((TextView)findViewById(R.id.ss)).setText(Utils.server.getCountry());
            } else {
                ((TextView)findViewById(R.id.ss)).setText("Selected server is " + Utils.server.getCountry());
            }
        }
    }

    @Override
    public void onResume() {
        LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver,new IntentFilter("connectionState"));
        if (vpnStart) {
            stopVpn();
        }
        updateCurrentServerIcon();
        super.onResume();
    }

    @Override
    public void onPause() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
        super.onPause();
    }

}