package com.tsi.navi.activity;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import com.tsi.navi.R;
import com.tsi.navi.api.ApiUtils;
import com.tsi.navi.api.TsiApiService;
import com.tsi.navi.databinding.ActivityApkDownloadBinding;
import com.tsi.navi.preferences.PrefManager;
import com.tsi.navi.util.BackPressedForFinish;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;

public class ApkDownloadActivity extends AppCompatActivity {
    private static final String TAG = ApkDownloadActivity.class.getSimpleName();

    private Context context;
    private ActivityApkDownloadBinding binding;
    private BackPressedForFinish backPressedForFinish;
    private DownloadApkFileTask downloadApkFileTask;
    private final String apkFileName = "tsi-navi.apk";
    private File apkFile;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.binding = ActivityApkDownloadBinding.inflate(getLayoutInflater());
        setContentView(this.binding.getRoot());

        this.context = this.getBaseContext();
        this.backPressedForFinish = new BackPressedForFinish(this);

        /*StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
*/
        askForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 101);

        String apkFileName = getIntent().getStringExtra("apkFileName").toString();
        downloadApkFile(apkFileName);
    }

    private void askForPermission(String permission, int requestCode) {
        if (ContextCompat.checkSelfPermission(ApkDownloadActivity.this, permission) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(ApkDownloadActivity.this, permission)) {
                ActivityCompat.requestPermissions(ApkDownloadActivity.this, new String[]{permission}, requestCode);

            } else {
                ActivityCompat.requestPermissions(ApkDownloadActivity.this, new String[]{permission}, requestCode);
            }
        } else if (ContextCompat.checkSelfPermission(ApkDownloadActivity.this, permission) == PackageManager.PERMISSION_DENIED) {
            Toast.makeText(getApplicationContext(), "권한 거부", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
            if (requestCode == 101) {
                Toast.makeText(this, "권한 획득", Toast.LENGTH_SHORT).show();
            }
        } else {
            Toast.makeText(this, "권한 거부", Toast.LENGTH_SHORT).show();
        }
    }

    private void downloadApkFile(String apkFileName) {
        TsiApiService tsiApiService = ApiUtils.getApiService(PrefManager.getApiUrl(this));
        tsiApiService.download(apkFileName).enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
                Log.e(TAG, "checkDeviceAuth: result code: " + response.code());
                if (response.isSuccessful() && response.code() == 200) {
                    Log.e(TAG, "downloadApk: result code: " + response.code());
                    if (response.isSuccessful() && response.code() == 200) {
                        Toast.makeText(getApplicationContext(), "response downloadApk", Toast.LENGTH_SHORT).show();
                        downloadApkFileTask = new DownloadApkFileTask();
                        downloadApkFileTask.execute(response.body());
                    } else {
                        alertDialogTerminate("어플리케이션 다운로드", "새로운 어플리케이션 다운로드에 실패하였습니다.");
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                alertDialogTerminate("어플리케이션 다운로드 API", "새로운 어플리케이션 다운로드에 실패하였습니다.(API 호출 실패)");
            }
        });
    }

    @SuppressLint("StaticFieldLeak")
    private class DownloadApkFileTask extends AsyncTask<ResponseBody, Pair<Integer, Long>, String> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            binding.progressBar.setProgress(0);
        }

        @Override
        protected String doInBackground(ResponseBody... urls) {
            return saveToDisk(urls[0]);
        }

        @SuppressLint("SetTextI18n")
        protected void onProgressUpdate(Pair<Integer, Long>... progress) {
            super.onProgressUpdate(progress);
            // 백그라운드 작업의 진행상태를 표시하기 위해서 호출하는

            if (progress[0].first == 100) {
                Toast.makeText(getApplicationContext(), "File downloaded successfully", Toast.LENGTH_SHORT).show();
                binding.progressBar.setProgress(100);
                binding.tvProgressPercent.setText("다운로드 100%");
            }

            if (progress[0].second > 0) {
                int currentProgress = (int) ((double) progress[0].first / (double) progress[0].second * 100);
                binding.progressBar.setProgress(currentProgress);
                binding.tvProgressPercent.setText("다운로드 " + currentProgress + "%");
            }

            if (progress[0].first == -1) {
                alertDialogTerminate("어플리케이션 다운로드", "새로운 어플리케이션 다운로드 중 오류로 실패하였습니다.\n관리자에게 문의 바랍니다.");
            }
        }

        public void doProgress(Pair<Integer, Long> progressDetails) {
            publishProgress(progressDetails);
        }

        @Override
        protected void onPostExecute(String result) {
            // Task 완료(doInBackground)
            if (result.equals("ok")) {
                Toast.makeText(getApplicationContext(), "다운로드가 완료되었습니다.", Toast.LENGTH_LONG).show();
                installApk();
            }
        }

        protected void onCancelled() {
            // cancel 메소드를 호출하면 자동으로 호출되는 메소드
            binding.progressBar.setProgress(0);
            binding.tvProgressPercent.setText("다운로드 진행 취소됨");
        }
    }

    private String saveToDisk(ResponseBody body) {
        try {
            File path = getFilesDir();
            path.mkdirs();
            this.apkFile = new File(path, this.apkFileName);
            if (this.apkFile.exists()) {
                this.apkFile.delete();
            }

            InputStream inputStream = null;
            OutputStream outputStream = null;

            try {
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(this.apkFile);
                byte data[] = new byte[4096];
                int count;
                int progress = 0;
                long fileSize = body.contentLength();
                while ((count = inputStream.read(data)) != -1) {
                    outputStream.write(data, 0, count);
                    progress += count;
                    Pair<Integer, Long> pairs = new Pair<>(progress, fileSize);
                    downloadApkFileTask.doProgress(pairs);
                }
                outputStream.flush();
                outputStream.close();

                Pair<Integer, Long> pairs = new Pair<>(100, 100L);
                downloadApkFileTask.doProgress(pairs);
                return "ok";
            } catch (IOException e) {
                e.printStackTrace();
                Pair<Integer, Long> pairs = new Pair<>(-1, Long.valueOf(-1));
                downloadApkFileTask.doProgress(pairs);
                return "IOException error";
            } finally {
                if (inputStream != null) inputStream.close();
                if (outputStream != null) outputStream.close();
            }
        }
        catch (IOException e) {
            e.printStackTrace();
            Pair<Integer, Long> pairs = new Pair<>(-1, Long.valueOf(-1));
            downloadApkFileTask.doProgress(pairs);
            return "IOException";
        }
    }

    public void installApk() {

        MediaScannerConnection.scanFile(getApplicationContext(), new String[]{
                this.apkFile.getAbsolutePath()}, null, new MediaScannerConnection.OnScanCompletedListener() {
            @Override
            public void onScanCompleted(String s, Uri uri) {
            }
        });

        Intent intent;
        Uri fileUri;
        // 다운로드한 파일 실행하여 업그레이드 진행하는 코드
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // Android Nougat ( 7.0 ) and later
            Log.e(TAG, "SDK_INT 24 이상 ");
            fileUri = FileProvider.getUriForFile(this.context, this.context.getApplicationContext().getPackageName() + ".fileprovider", this.apkFile);
            //Intent intent = new Intent(Intent.ACTION_VIEW);
            intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
            getApplicationContext().startActivity(intent);
            finish();
        }
        else {
            Log.e(TAG, "SDK_INT 23 이하 ");
            fileUri = Uri.fromFile(this.apkFile);
            intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
            getApplicationContext().startActivity(intent);
            finish();
        }
    }

    // 다이얼로그를 띄우고 앱을 종료한다.
    private void alertDialogTerminate(String title, String message) {
        Toast.makeText(getApplicationContext(), title, Toast.LENGTH_SHORT).show();
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(title);
        builder.setMessage(message + "\n앱을 종료 합니다.");
        builder.setIcon(R.drawable.ic_launcher_foreground);
        builder.setPositiveButton("확인", new DialogInterface.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                // 앱 종료
                backPressedForFinish.terminate();
            }
        });
        AlertDialog dialog = builder.create();
        dialog.show();
    }

    @Override
    public void onBackPressed() {
        this.backPressedForFinish.onBackPressed(true);
    }

}
