package com.birdsounds.identify;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


@SuppressWarnings("ResultOfMethodCallIgnored")
public class Downloader {
    static final String modelFILE = "modelfx.tflite";
    static final String metaModelFILE = "metaModelfx.tflite";
    static final String modelURL = "https://raw.githubusercontent.com/woheller69/whoBIRD-TFlite/master/BirdNET_GLOBAL_6K_V2.4_Model_FP16.tflite";
    static final String model32URL = "https://raw.githubusercontent.com/woheller69/whoBIRD-TFlite/master/BirdNET_GLOBAL_6K_V2.4_Model_FP32.tflite";
    static final String metaModelURL = "https://raw.githubusercontent.com/woheller69/whoBIRD-TFlite/master/BirdNET_GLOBAL_6K_V2.4_MData_Model_FP16.tflite";
    static final String modelMD5 = "b1c981fe261910b473b9b7eec9ebcd4e";
    static final String model32MD5 = "6c7c42106e56550fc8563adb31bc120e";
    static final String metaModelMD5 ="f1a078ae0f244a1ff5a8f1ccb645c805";

    public static boolean checkModels(final Activity activity) {
        File modelFile = new File(activity.getDir("filesdir", Context.MODE_PRIVATE) + "/" + modelFILE);
        File metaModelFile = new File(activity.getDir("filesdir", Context.MODE_PRIVATE) + "/" + metaModelFILE);
        String calcModelMD5 = "";
        String calcMetaModelMD5 = "";
        if (modelFile.exists()) {
            try {
                byte[] data = Files.readAllBytes(Paths.get(modelFile.getPath()));
                byte[] hash = MessageDigest.getInstance("MD5").digest(data);
                calcModelMD5 = new BigInteger(1, hash).toString(16);
            } catch (IOException | NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }
        if (metaModelFile.exists()) {
            try {
                byte[] data = Files.readAllBytes(Paths.get(metaModelFile.getPath()));
                byte[] hash = MessageDigest.getInstance("MD5").digest(data);
                calcMetaModelMD5 = new BigInteger(1, hash).toString(16);
            } catch (IOException | NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }

        if (modelFile.exists() && !(calcModelMD5.equals(modelMD5) || calcModelMD5.equals(model32MD5))) modelFile.delete();
        if (metaModelFile.exists() && !calcMetaModelMD5.equals(metaModelMD5)) metaModelFile.delete();

        return (calcModelMD5.equals(modelMD5) || calcModelMD5.equals(model32MD5)) && calcMetaModelMD5.equals(metaModelMD5);
    }

    public static void downloadModels(final Activity activity) {
        File modelFile = new File(activity.getDir("filesdir", Context.MODE_PRIVATE) + "/" + modelFILE);
        Log.d("Heyy","Model file checking");
        if (!modelFile.exists()) {
            Log.d("whoBIRD", "model file does not exist");
            Thread thread = new Thread(() -> {
                try {
                    URL url;
                    if (false) url = new URL(model32URL);
                    else url = new URL(modelURL);

                    Log.d("whoBIRD", "Download model");

                    URLConnection ucon = url.openConnection();
                    Log.d("whoBIRD", "i am here");
                    ucon.setReadTimeout(5000);
                    ucon.setConnectTimeout(10000);

                    InputStream is = ucon.getInputStream();
                    BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);

                    modelFile.createNewFile();

                    FileOutputStream outStream = new FileOutputStream(modelFile);
                    byte[] buff = new byte[5 * 1024];
                    int len;

                    while ((len = inStream.read(buff)) != -1) {
                        outStream.write(buff, 0, len);
                    }

                    outStream.flush();
                    outStream.close();
                    inStream.close();

                    String calcModelMD5="";
                    if (modelFile.exists()) {
                        byte[] data = Files.readAllBytes(Paths.get(modelFile.getPath()));
                        byte[] hash = MessageDigest.getInstance("MD5").digest(data);
                        calcModelMD5 = new BigInteger(1, hash).toString(16);
                    } else {
                        throw new IOException();  //throw exception if there is no modelFile at this point
                    }

                    if (!(calcModelMD5.equals(modelMD5) || calcModelMD5.equals(model32MD5) )){
                        modelFile.delete();
                        activity.runOnUiThread(() -> {
                            Toast.makeText(activity, activity.getResources().getString(R.string.error_download), Toast.LENGTH_SHORT).show();
                        });
                    } else {
                        activity.runOnUiThread(() -> {

                        });
                    }
                } catch (NoSuchAlgorithmException | IOException i) {
                    activity.runOnUiThread(() -> Toast.makeText(activity, activity.getResources().getString(R.string.error_download), Toast.LENGTH_SHORT).show());
                    modelFile.delete();
                }
            });
            thread.start();

            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            Log.d("whoBIRD","model exists");
            activity.runOnUiThread(() -> {

            });
        }

        File metaModelFile = new File(activity.getDir("filesdir", Context.MODE_PRIVATE) + "/" + metaModelFILE);
        if (!metaModelFile.exists()) {
            Log.d("whoBIRD", "meta model file does not exist");
            Thread thread = new Thread(() -> {
                try {
                    URL url = new URL(metaModelURL);
                    Log.d("whoBIRD", "Download meta model");

                    URLConnection ucon = url.openConnection();
                    ucon.setReadTimeout(5000);
                    ucon.setConnectTimeout(10000);

                    InputStream is = ucon.getInputStream();
                    BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);

                    metaModelFile.createNewFile();

                    FileOutputStream outStream = new FileOutputStream(metaModelFile);
                    byte[] buff = new byte[5 * 1024];

                    int len;
                    while ((len = inStream.read(buff)) != -1) {
                        outStream.write(buff, 0, len);
                    }
                    outStream.flush();
                    outStream.close();
                    inStream.close();

                    String calcMetaModelMD5="";
                    if (metaModelFile.exists()) {
                        byte[] data = Files.readAllBytes(Paths.get(metaModelFile.getPath()));
                        byte[] hash = MessageDigest.getInstance("MD5").digest(data);
                        calcMetaModelMD5 = new BigInteger(1, hash).toString(16);
                    } else {
                        throw new IOException();  //throw exception if there is no modelFile at this point
                    }

                    if (!calcMetaModelMD5.equals(metaModelMD5)){
                        metaModelFile.delete();
                        activity.runOnUiThread(() -> {
                            Toast.makeText(activity, activity.getResources().getString(R.string.error_download), Toast.LENGTH_SHORT).show();
                        });
                    } else {
                        activity.runOnUiThread(() -> {
                               });
                    }
                } catch (NoSuchAlgorithmException | IOException i) {
                    activity.runOnUiThread(() -> Toast.makeText(activity, activity.getResources().getString(R.string.error_download), Toast.LENGTH_SHORT).show());
                    metaModelFile.delete();
                    Log.w("whoBIRD", activity.getResources().getString(R.string.error_download), i);
                }
            });
            thread.start();
            try {
                thread.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            Log.d("whoBIRD", "meta file exists");
            activity.runOnUiThread(() -> {
             });
        }

    }
}