package com.meerkat.laura.fakescannerapp;


import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import ch.qos.logback.classic.android.BasicLogcatConfigurator;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import meerkat.crypto.DigitalSignatureGenerator;
import meerkat.crypto.concrete.ECDSADeterministicSignature;
import meerkat.pollingstation.PollingStationScanner;
import meerkat.pollingstation.ScannerClientAPI;
import meerkat.protobuf.PollingStation;

import java.math.BigInteger;
import java.util.Date;

import static com.meerkat.laura.fakescannerapp.R.xml.preferences;


public class MainActivity extends AppCompatActivity implements View.OnClickListener,  SharedPreferences.OnSharedPreferenceChangeListener {

    static {
        BasicLogcatConfigurator.configureDefaultContext();
    }

    final public static String SCANNER_NAME = "AndroidScanner";
    SharedPreferences sharedPref;

    Button scanBtn;
    TextView formatTxt, contentTxt, responseTxt, serverStatus;
    PollingStationScanner.ScannerClient scannerClient;
    DigitalSignatureGenerator signer;

    class AsyncScanConnect extends AsyncTask<Void, Void, Boolean> {
        PollingStation.ConnectionServerData serverData;

        public AsyncScanConnect(PollingStation.ConnectionServerData connectionServerData) {
            this.serverData = connectionServerData;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            serverStatus.setTextColor(Color.BLUE);
            serverStatus.setText("Connecting to " + serverData.getServerUrl());
        }

        @Override
        protected Boolean doInBackground(Void... foo) {
            try {
                return scannerClient.connect(serverData);
            } catch (RuntimeException e) {
                Log.e("MainActivity", "Exception during connect: " + e.toString());
                return false;
            }
        }

        @Override
        protected void onPostExecute(Boolean res) {
            super.onPostExecute(res);
            if (res) {
                serverStatus.setTextColor(Color.GREEN);
                serverStatus.setText("Connected to " + serverData.getServerUrl());
            } else {
                serverStatus.setTextColor(Color.RED);
                serverStatus.setText("Connection failed: " + serverData.getServerUrl());
            }
        }
    }

    class AsyncScanSend extends AsyncTask<Void, Void, Boolean> {
        Message data;

        public AsyncScanSend(Message data) {
            this.data = data;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            serverStatus.setTextColor(Color.BLUE);
            serverStatus.setText("Sending to server...");
        }

        @Override
        protected Boolean doInBackground(Void... foo) {
            try {
                if (data instanceof PollingStation.ScannedBallot) {
                    return scannerClient.newScan((PollingStation.ScannedBallot) data);
                } else if (data instanceof PollingStation.ScanError) {
                    return scannerClient.reportError((PollingStation.ScanError) data);
                } else {
                    Log.e("MainActivity", "Trying to send invalid message to scanner");
                    return false;
                }
            } catch (RuntimeException e) {
                Log.e("MainActivity", "Exception during send: " + e.toString());
                return false;
            }
        }

        @Override
        protected void onPostExecute(Boolean res) {
            super.onPostExecute(res);
            if (res) {
                serverStatus.setTextColor(Color.GREEN);
                serverStatus.setText("Sent successfully");
                Log.i("MainActivity", "post submitted to API.");
            } else {
                serverStatus.setTextColor(Color.RED);
                serverStatus.setText("Send failed");
                Log.e("MainActivity", "Unable to submit post to API.");
            }
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.action_settings:
                Intent i = new Intent(this, SettingsActivity.class);
                startActivity(i);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    void setNewScannerClientAPI(SharedPreferences sharedPref) {
        String pscUrlString = sharedPref.getString(SettingsFragment.PSC_URL, "");
        long nonce = 0;

        try {
            nonce = Long.parseLong(sharedPref.getString(SettingsFragment.PSC_NONCE, "0"));
        } catch (NumberFormatException e) {
            // Ignore
        }

        if (pscUrlString.isEmpty())
            return;

        PollingStation.ConnectionServerData serverData = PollingStation.ConnectionServerData.newBuilder()
                .setServerUrl(pscUrlString)
                .setNonce(nonce)
                .build();

        new AsyncScanConnect(serverData).execute();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        signer = new ECDSADeterministicSignature();
        signer.generateSigningCertificate(BigInteger.ONE, new Date(System.currentTimeMillis()),
                new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365), SCANNER_NAME);
        scannerClient = new ScannerClientAPI(signer);

        PreferenceManager.setDefaultValues(this, preferences, false);
        sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
        sharedPref.registerOnSharedPreferenceChangeListener(this);

        scanBtn = (Button) findViewById(R.id.scan_button);
        formatTxt = (TextView) findViewById(R.id.scan_format);
        contentTxt = (TextView) findViewById(R.id.scan_content);
        responseTxt = (TextView) findViewById(R.id.server_response);
        serverStatus = (TextView) findViewById(R.id.serverStatus);

        setNewScannerClientAPI(sharedPref);
        scanBtn.setOnClickListener(this);
    }

    public void onClick(View v) {
        if (v.getId() == R.id.scan_button) {
            IntentIntegrator scanIntegrator = new IntentIntegrator(this);
            formatTxt.setText("Initiating scan...");
            scanIntegrator.initiateScan();
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
        if (scanningResult != null) {
            String scanContent = scanningResult.getContents();
            byte[] rawBytes = scanningResult.getRawBytes();
            String scanFormat = scanningResult.getFormatName();
            formatTxt.setText("FORMAT: " + scanFormat);
            contentTxt.setText("CONTENT: " + scanContent + "sending data to server...");
//            sendPost(rawBytes);
            sendPost(scanContent);
        } else {
            Toast toast = Toast.makeText(getApplicationContext(),
                    "No scan data received!", Toast.LENGTH_SHORT);
            toast.show();
        }
    }

    //    public void sendPost(byte[] body) {
    public void sendPost(String scanContent) {

        try {
            PollingStation.ScannedBallot scannedBallot = PollingStation.ScannedBallot.parseFrom(Base64.decode(scanContent.getBytes(), Base64.DEFAULT));
            //
            //        PollingStation.ScannedData scannedData = PollingStation.ScannedData.newBuilder()
            //                .setChannel(ByteString.copyFrom(body))
            //                .build();

            new AsyncScanSend(scannedBallot).execute();
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
    }

    public void showResponse(String response) {
        responseTxt.setText(response);
    }


    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){
        setNewScannerClientAPI(sharedPreferences);
    }

}
