package uprrp.tania.activities;

import android.Manifest;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

import org.researchstack.backbone.StorageAccess;
import org.researchstack.backbone.model.ConsentDocument;
import org.researchstack.backbone.model.ConsentSection;
import org.researchstack.backbone.model.ConsentSignature;
import org.researchstack.backbone.result.TaskResult;
import org.researchstack.backbone.step.ConsentDocumentStep;
import org.researchstack.backbone.step.ConsentSignatureStep;
import org.researchstack.backbone.step.ConsentVisualStep;
import org.researchstack.backbone.task.OrderedTask;
import org.researchstack.backbone.task.Task;
import org.researchstack.backbone.ui.ViewTaskActivity;
import org.researchstack.backbone.ui.step.layout.ConsentSignatureStepLayout;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import uprrp.tania.GlobalValues;
import uprrp.tania.R;
import uprrp.tania.networking.SendConsentForm;
import uprrp.tania.utils.URLEventListener;

public class GettingStartedActivity extends AppCompatActivity {

    private static final String TAG = "GettingStartedActivity";
    private static final int REQUEST_CONSENT = 0;
    public static final String VISUAL_CONSENT_IDENTIFIER = "visual_consent_identifier";
    public static final String CONSENT_DOC = "consent_doc";
//    public static final String SIGNATURE_FORM_STEP = "form_step";
//    public static final String NAME = "name";
    public static final String CONSENT = "consent";
    public static final String SIGNATURE = "signature";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        // Constructor stuff
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_getting_started);

        // Get permission to write to external storage - files
        String[] permissions = { Manifest.permission.WRITE_EXTERNAL_STORAGE };
        requestPermissions(permissions, 1);

        // If user is already logged in, go to MainActivity
        SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
        boolean needsToRegister = prefs.getBoolean("needsToRegister", true);
        if(!needsToRegister) {
            Intent intent = new Intent(GettingStartedActivity.this, MainActivity.class);
            startActivity(intent);
            return;
        }

        // Attach onClick listeners to buttons
        Button createAccountButton = findViewById(R.id.buttonCreateAccount);
        Button loginAccountButton = findViewById(R.id.buttonRecoverAccount);
        createAccountButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
        loginAccountButton.setTransformationMethod(null); // TODO: this is a workaround I found, any other acceptable solution is welcome
        createAccountButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    launchConsent();
            }
        });
        loginAccountButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(GettingStartedActivity.this, AccountRecoveryActivity.class);
                startActivity(intent);
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode == REQUEST_CONSENT && resultCode == RESULT_OK) {
            processConsentResult((TaskResult) data.getSerializableExtra(ViewTaskActivity.EXTRA_TASK_RESULT));
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions [], int[] grantResults) {
        if(requestCode == 1) {
            if(grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(getApplicationContext(), "Permission for writing to external storage: DENIED", Toast.LENGTH_LONG).show();
            }
        }
    }


    private void processConsentResult(TaskResult result) {

        boolean consented = (boolean) result.getStepResult(CONSENT_DOC).getResult();
        StorageAccess.getInstance().getAppDatabase().saveTaskResult(result);

        if(consented) {

            // Get signature in base64
            TaskResult taskResult = StorageAccess.getInstance()
                    .getAppDatabase()
                    .loadLatestTaskResult(CONSENT);
            String signatureBase64 = (String) taskResult.getStepResult(SIGNATURE)
                    .getResultForIdentifier(ConsentSignatureStepLayout.KEY_SIGNATURE);

            // Get signature date
            String signatureDate = (String) result.getStepResult(SIGNATURE)
                    .getResultForIdentifier(ConsentSignatureStepLayout.KEY_SIGNATURE_DATE);

            // Use signature to get encoded consent form
            byte[] signatureBytes = Base64.decode(signatureBase64, Base64.DEFAULT);
            String consentFormBase64 = this.createPdf(signatureBytes, signatureDate);

            // Send JSON with consent form, signature date, and token
            String deviceToken = GlobalValues.getInstance().getDeviceToken();
            this.sendConsentForm(deviceToken, consentFormBase64, signatureDate);

            // Save consent signature and date separately on preferences
            SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
            SharedPreferences.Editor editor = prefs.edit();
            editor.putString("consentSignature", signatureBase64);
            editor.putString("consentDate", signatureDate);
            editor.apply();

            // Prompt user to register as student
            Intent registration = new Intent(this, RegisterActivity.class);
            startActivity(registration);

        }

    }

    private void sendConsentForm(String deviceToken, String consentFormBase64, String signatureDate) {
        SendConsentForm sendConsentFormTask = new SendConsentForm(new URLEventListener() {
            @Override
            public void onSuccess() {
                Toast.makeText(getApplicationContext(), "Sent consent form to server!", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(Exception e) {
                Toast.makeText(getApplicationContext(), "Couldn't send consent form to server!", Toast.LENGTH_LONG).show();
                Log.e(TAG, "Couldn't send consent form to server!");
                e.printStackTrace();
            }
        });

        sendConsentFormTask.execute(deviceToken, consentFormBase64, signatureDate);
    }

    private void launchConsent() {


        // Consent Section 1 - Overview (Welcome)
        ConsentSection section1 = new ConsentSection(ConsentSection.Type.Overview);
        section1.setTitle(getString(R.string.overviewTitleText));
        section1.setSummary(getString(R.string.overviewConsentSectionSummaryText));
        section1.setContent(getString(R.string.overviewConsentSectionContentText));

        ConsentVisualStep visualStep1 = new ConsentVisualStep(VISUAL_CONSENT_IDENTIFIER);
        visualStep1.setStepTitle(R.string.rsb_consent);
        visualStep1.setSection(section1);
        visualStep1.setNextButtonString("Next");


        // Consent Section 2 - Time Commitment
        ConsentSection section2 = new ConsentSection(ConsentSection.Type.TimeCommitment);
        section2.setTitle(getString(R.string.timeCommitmentTitleText));
        section2.setSummary(getString(R.string.timeCommitmentConsentSectionSummaryText));
        section2.setContent(getString(R.string.timeCommitmentConsentSectionContentText));

        ConsentVisualStep visualStep2 = new ConsentVisualStep("visual_step_2");
        visualStep2.setStepTitle(R.string.rsb_consent);
        visualStep2.setSection(section2);
        visualStep2.setNextButtonString("Next");


        // Consent Section 3 - Data Gathering
        ConsentSection section3 = new ConsentSection(ConsentSection.Type.DataGathering);
        section3.setTitle(getString(R.string.dataGatheringTitleText));
        section3.setSummary(getString(R.string.dataGatheringConsentSectionSummaryText));
        section3.setContent(getString(R.string.dataGatheringConsentSectionContentText));

        ConsentVisualStep visualStep3 = new ConsentVisualStep("visual_step_3");
        visualStep3.setStepTitle(R.string.rsb_consent);
        visualStep3.setSection(section3);
        visualStep3.setNextButtonString("Next");


        // Consent Section 4 - Privacy
        ConsentSection section4 = new ConsentSection(ConsentSection.Type.Privacy);
        section4.setTitle(getString(R.string.privacyTitleText));
        section4.setSummary(getString(R.string.privacyConsentSectionSummaryText));
        section4.setContent(getString(R.string.privacyConsentSectionContentText));

        ConsentVisualStep visualStep4 = new ConsentVisualStep("visual_step_4");
        visualStep4.setStepTitle(R.string.rsb_consent);
        visualStep4.setSection(section4);
        visualStep4.setNextButtonString("Next");


        // Consent Section 5 - Data Use
        ConsentSection section5 = new ConsentSection(ConsentSection.Type.DataUse);
        section5.setTitle(getString(R.string.dataUseTitleText));
        section5.setSummary(getString(R.string.dataUseConsentSectionSummaryText));
        section5.setContent(getString(R.string.dataUseConsentSectionContentText));

        ConsentVisualStep visualStep5 = new ConsentVisualStep("visual_step_5");
        visualStep5.setStepTitle(R.string.rsb_consent);
        visualStep5.setSection(section5);
        visualStep5.setNextButtonString("Next");


        // Create consent signature object and set what info is required
        ConsentSignature signature = new ConsentSignature();
        signature.setRequiresName(true);
        signature.setRequiresSignatureImage(true);


        // Create our HTML to show the user and have them accept or decline.
        String consentHtmlString =

                "<br>" +

                "<div style='padding: 10px;' class='header'>" +
                    "<h1 style='text-align: center; font-family:sans-serif-light;'>" + getString(R.string.rsb_consent_review_title) + "</h1>" +
                    "<p style='text-align: center'>" + getString(R.string.rsb_consent_review_instruction) + "</p>" +
                "</div>" +

                "<br>" +

                "<div>" +
                    "<h2>" + getString(R.string.overviewTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentOverview) + "</p>" +

                    "<h2>" + getString(R.string.timeCommitmentTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentTimeCommitment) + "</p>" +

                    "<h2>" + getString(R.string.dataGatheringTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentDataGathering) + "</p>" +

                    "<h2>" + getString(R.string.privacyTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentPrivacy) + "</p>" +

                    "<h2>" + getString(R.string.dataUseTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentDataUse) + "</p>" +

                    "<h2>" + getString(R.string.generalTitleText) + "</h2>" +
                    "<p align='justify'>" + getString(R.string.consentGeneral) + "</p>" +
                    "<p align='justify'>" + getString(R.string.consentConclusion) + "</p>" +
                "</div>";


        // Create the consent document step and pass in our HTML
        ConsentDocumentStep documentStep = new ConsentDocumentStep(CONSENT_DOC);
        documentStep.setConsentHTML(consentHtmlString);
        documentStep.setConfirmMessage(getString(R.string.rsb_consent_review_reason));


        // Create Consent form step, to get users first & last name
//        FormStep formStep = new FormStep(SIGNATURE_FORM_STEP,
//                "Form Title",
//                "Form step description");
//        formStep.setStepTitle(R.string.rsb_consent);
//
//        TextAnswerFormat format = new TextAnswerFormat();
//        format.setIsMultipleLines(false);
//
//        QuestionStep fullName = new QuestionStep(NAME, "Full name", format);
//        formStep.setFormSteps(Collections.singletonList(fullName));


        // Create the consent signature step (so that user can sign)
        ConsentSignatureStep signatureStep = new ConsentSignatureStep(SIGNATURE);
        signatureStep.setStepTitle(R.string.rsb_consent);
        signatureStep.setTitle(getString(R.string.rsb_consent_signature_title));
        signatureStep.setText(getString(R.string.rsb_consent_signature_instruction));
        signatureStep.setSignatureDateFormat(signature.getSignatureDateFormatString());
        signatureStep.setOptional(false);
        signatureStep.setStepLayoutClass(ConsentSignatureStepLayout.class);


        // Create consent document
        ConsentDocument document = new ConsentDocument();
        document.setTitle(getString(R.string.appName) + " Consent");
        document.setSignaturePageTitle(R.string.rsb_consent);
        document.addSignature(signature);
        document.getHtmlReviewContent();


        // Finally, create and present a task including these steps.
        Task consentTask = new OrderedTask(CONSENT,
                visualStep1,
                visualStep2,
                visualStep3,
                visualStep4,
                visualStep5,
                documentStep,
//                formStep,
                signatureStep);


        // Launch using the ViewTaskActivity and make sure to listen for the activity result
        Intent intent = ViewTaskActivity.newIntent(this, consentTask);
        startActivityForResult(intent, REQUEST_CONSENT);

    }

    // TODO: IO should be moved to a background task
    private String createPdf(byte[] signatureBytes, String consentDate) {

        try {

            // Open document
            Document document = new Document();
            String filePath = Environment.getExternalStorageDirectory().getPath() + getString(R.string.consentFileName);
            PdfWriter.getInstance(document, new FileOutputStream(filePath));
            document.open();


            // Define fonts and offsets
            Font titleFont = new Font(Font.FontFamily.HELVETICA, 20, Font.BOLD, BaseColor.BLACK);
            Font subtitleFont = new Font(Font.FontFamily.HELVETICA, 14, Font.BOLD, BaseColor.BLACK);
            Font signatureSectionFont = new Font(Font.FontFamily.HELVETICA, 12, Font.BOLDITALIC, BaseColor.BLACK);
            int signatureOffsetX = 145;
            int signatureOffsetY = -24;


            // Consent Title
            Chunk titleChunk = new Chunk("Consent form:\n" + getString(R.string.appName), titleFont);
            Paragraph title = new Paragraph(titleChunk);
            title.setAlignment(Element.ALIGN_CENTER);
            document.add(title);

            Paragraph newLine = new Paragraph("\n"); // TODO: find out if this is necessary
            document.add(newLine);


            // Consent Section 1 - Overview (Welcome)
            String consentOverview = getString(R.string.consentOverview);
            Paragraph paragraph1 = new Paragraph(consentOverview);
            paragraph1.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph1);


            // Consent Section 2 - Time Commitment
            Chunk subtitle1 = new Chunk(getString(R.string.timeCommitmentTitleText), subtitleFont);
            Paragraph timeCommitmentTitle = new Paragraph(subtitle1);
            document.add(timeCommitmentTitle);

            String consentTimeCommitment = getString(R.string.consentTimeCommitment);
            Paragraph paragraph2 = new Paragraph(consentTimeCommitment);
            paragraph2.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph2);


            // Consent Section 3 - Data Gathering
            Chunk subtitle2 = new Chunk(getString(R.string.dataGatheringTitleText), subtitleFont);
            Paragraph dataGatheringTitle = new Paragraph(subtitle2);
            document.add(dataGatheringTitle);

            String consentDataGathering = getString(R.string.consentDataGathering);
            Paragraph paragraph3 = new Paragraph(consentDataGathering);
            paragraph3.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph3);


            // Consent Section 4 - Privacy
            Chunk subtitle3 = new Chunk(getString(R.string.privacyTitleText), subtitleFont);
            Paragraph privacyTitle = new Paragraph(subtitle3);
            document.add(privacyTitle);

            String consentPrivacy = getString(R.string.consentPrivacy);
            Paragraph paragraph4 = new Paragraph(consentPrivacy);
            paragraph4.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph4);


            // Consent Section 5 - Data Use
            Chunk subtitle4 = new Chunk(getString(R.string.dataUseTitleText), subtitleFont);
            Paragraph useOfDataTitle = new Paragraph(subtitle4);
            document.add(useOfDataTitle);

            String consentUseOfData = getString(R.string.consentDataUse);
            Paragraph paragraph5 = new Paragraph(consentUseOfData);
            paragraph5.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph5);


            // Consent Section 6 - General & Conclusion
            Chunk subtitle5 = new Chunk(getString(R.string.generalTitleText), subtitleFont);
            Paragraph generalTitle = new Paragraph(subtitle5);
            document.add(generalTitle);

            String consentGeneral = getString(R.string.consentGeneral);
            Paragraph paragraph6 = new Paragraph(consentGeneral);
            paragraph6.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph6);

            String consentConclusion = getString(R.string.consentConclusion);
            Paragraph paragraph7 = new Paragraph(consentConclusion);
            paragraph7.setAlignment(Element.ALIGN_JUSTIFIED);
            document.add(paragraph7);


            // Signature Section
            Chunk participantSignature = new Chunk("Participant's signature:", signatureSectionFont);
            Paragraph paragraph8 = new Paragraph(participantSignature);
            document.add(paragraph8);

            Image consentSignatureImage = Image.getInstance(signatureBytes);
            Chunk signatureImage = new Chunk(consentSignatureImage, signatureOffsetX, signatureOffsetY);
            Paragraph paragraph11 = new Paragraph(signatureImage);
            document.add(paragraph11);

            Chunk signatureDate = new Chunk("Signed on: " + consentDate, signatureSectionFont);
            Paragraph paragraph9 = new Paragraph(signatureDate);
            document.add(paragraph9);


            // Finish and store document
            document.close();


            // Read document back, encode to base64 and return
            // TODO: find out if we really need to read it back,
            //  cause AndroidStudio says its value is ignored
            File file = new File(filePath);
            int size = (int) file.length();
            byte[] consentBytes = new byte[size];

            BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(file));
            buffer.read(consentBytes, 0, consentBytes.length);
            buffer.close();

            return Base64.encodeToString(consentBytes, Base64.DEFAULT);

        } catch (FileNotFoundException e) {
            Log.e(TAG, "Couldn't find generated consent form!");
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            Log.e(TAG, "Couldn't read back generated consent form!");
            e.printStackTrace();
            return null;
        } catch (BadElementException e) {
            Log.e(TAG, "Couldn't create a consent form element!");
            e.printStackTrace();
            return null;
        } catch (DocumentException e) {
            Log.e(TAG, "Something went wrong while fiddling with the consent form creation!");
            e.printStackTrace();
            return null;
        } catch (Exception e) {
            Log.wtf(TAG, "Call to launchConsent() went wrong!");
            e.printStackTrace();
            return null;
        }

    }
}
