package com.tsi.navi.activity;

import static android.content.DialogInterface.OnClickListener;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import com.naver.maps.geometry.LatLng;
import com.tsi.navi.R;
import com.tsi.navi.TsiNaviApplication;
import com.tsi.navi.api.ApiUtils;
import com.tsi.navi.api.TsiApiService;
import com.tsi.navi.api.auth.AuthentificationResult;
import com.tsi.navi.api.auth.VersionVo;
import com.tsi.navi.api.node.NodeStatus;
import com.tsi.navi.api.node.NodeStatusResult;
import com.tsi.navi.api.register.RegisterDevice;
import com.tsi.navi.api.register.RegisterDeviceResult;
import com.tsi.navi.database.DbHelper;
import com.tsi.navi.database.DbQuery;
import com.tsi.navi.databinding.ActivityInitBinding;
import com.tsi.navi.helper.PermissionHelper;
import com.tsi.navi.preferences.PrefManager;
import com.tsi.navi.util.BackPressedForFinish;
import com.tsi.navi.vo.NodeVo;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;

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

    public static final int REGISTER_DEVICE_CODE = 200;

    private String deviceId;
    private ActivityInitBinding binding;
    private BackPressedForFinish backPressedForFinish;
    private TsiApiService tsiApiService;
    private PermissionHelper permissionHelper;
    private ActivityResultLauncher<Intent> launchResult;

    @SuppressLint({"HardwareIds", "SetTextI18n"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityInitBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // 전역 변수 초기화
        try {
            PackageInfo pInfo = null;
            pInfo = getPackageManager().getPackageInfo(this.getPackageName(), 0);
            //int versionCode = pInfo.versionCode;
            String versionName = pInfo.versionName; // build.gradle 에 기록된 VersionName
            PrefManager.setAppVersion(this, versionName);
            binding.textAppVersion.setText("version: " + PrefManager.getAppVersion(this));
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        this.deviceId = PrefManager.getDeviceId(this);

        /*DeviceUuidFactory ff = new DeviceUuidFactory(this);
        Log.e(TAG, "DeviceId1: " + ff.getDeviceUuid());
        try {
            Log.e(TAG, "DeviceId2: " + UUID.nameUUIDFromBytes(this.deviceId.getBytes("utf8")));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }*/
        Log.e(TAG, "API URL: " + PrefManager.getApiUrl(this));
        this.backPressedForFinish = new BackPressedForFinish(this);
        this.tsiApiService = ApiUtils.getApiService(PrefManager.getApiUrl(this));
        // 액티비티 콜백 함수
        this.launchResult = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                new ActivityResultCallback<ActivityResult>() {
                    @Override
                    public void onActivityResult(ActivityResult result) {
                        Log.e(TAG, "result.code: " + String.valueOf(result.getResultCode()));
                        Log.e(TAG, result.toString());
                        if (result.getResultCode() != RESULT_OK) {
                            // 앱 종료
                            Log.e(TAG, "onActivityResult-failed");
                            backPressedForFinish.terminate();
                            return;
                        }

                        Intent intent = result.getData();
                        if (intent == null) {
                            // 최초 앱 설치 권한 설정
                            checkPermission();
                        }
                        else {
                            intent.putExtra("dialogType", InitActivity.REGISTER_DEVICE_CODE);
                            int dialogType = intent.getIntExtra("dialogType", 0);
                            Log.e(TAG, "dialogType: " + String.valueOf(dialogType));
                            if (dialogType == REGISTER_DEVICE_CODE) {
                                Log.e(TAG, "REGISTER_DEVICE_CODE");
                                // 디바이스 등록
                                RegisterDevice deviceInfo = RegisterDevice.builder()
                                        .deviceId(deviceId)
                                        .company(intent.getStringExtra("company"))
                                        .manager(intent.getStringExtra("manager"))
                                        .phone(intent.getStringExtra("phone"))
                                        .email(intent.getStringExtra("email"))
                                        .build();

                                registerDeviceInfo(deviceInfo);
                            }
                            else {

                            }
                        }
                    }
                });

        Log.e(TAG, "onCreate - 1");

        // 앱설치권한 확인
        checkAppInstallation();
    }

    private void updateApk(String apkFileName) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("어플리케이션 업데이트");
        builder.setMessage("어플리케이션이 업데이트 되었습니다.\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) {
                downloadApk(apkFileName);
            }
        });

        builder.setNegativeButton("취소", 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();
    }

    private void downloadApk(String apkFileName) {

        // 이전 데이터베이스 파일을 삭제한다.
        DbHelper.deleteDatabase(this);

        Intent intent = new Intent(getApplicationContext(), ApkDownloadActivity.class);
        intent.putExtra("apkFileName", apkFileName);
        startActivity(intent);
        finish();
    }

    // 앱설치권한 확인
    public void checkAppInstallation() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            Log.e(TAG, "checkAppInstallation - 1");
            PackageManager packageManager = getApplicationContext().getPackageManager();
            if (!packageManager.canRequestPackageInstalls())
            {
                AlertDialog.Builder b = new AlertDialog.Builder(this);//, android.R.style.Theme_DeviceDefault_Light_Dialog);
                b.setCancelable(false); // 백버튼 불가, 바탕화면 클릭 불가
                b.setTitle("알림");
                b.setMessage("보안을 위해 스마트폰 환경설정의 '앱 설치 허용' 을 설정해 주시기 바랍니다");
                b.setCancelable(false);
                b.setPositiveButton("설정하기", new OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                        intent.setData(Uri.parse("package:" + getPackageName()));
                        launchResult.launch(intent);
                    }
                });
                b.show();
            }
            else {
                Log.e(TAG, "checkAppInstallation - 2");
                checkPermission();
            }
        }
        else {
            // 앱 사용 퍼미션 확인
            Log.e(TAG, "checkAppInstallation - 3");
            checkPermission();
        }
    }

    // 앱 사용 퍼미션 확인
    @SuppressLint("ObsoleteSdkInt")
    public void checkPermission() {
        Log.e(TAG, "checkPermission");
        if (Build.VERSION.SDK_INT >= 23) {
            permissionHelper = new PermissionHelper(this, this);
            if (permissionHelper.checkPermissions()) {
                checkDeviceAuth();
            }
            else {
                permissionHelper.requestPermissions();
            }
        }
        else {
            checkDeviceAuth();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grandResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grandResults);
        if (this.permissionHelper.permissionResult(requestCode, permissions, grandResults)) {
            // 모든 권한이 허가되었으므로 앱 시작
            checkDeviceAuth();
        }
        else {
            if (this.permissionHelper.isRequestPermissionAll()) {
                this.backPressedForFinish.terminate();
            }
            else {
                this.permissionHelper.requestPermissions();
            }
        }
    }

    // 디바이스 권한 확인
    // 1. 디바이스 권한이 등록되어 있는지 확인한다.
    public void checkDeviceAuth() {
        Log.e(TAG, "checkDeviceAuth");

        // 디바이스 인증 요청
        this.tsiApiService.getDeviceAuth(this.deviceId).enqueue(new Callback<AuthentificationResult>() {
            @Override
            public void onResponse(Call<AuthentificationResult> call, retrofit2.Response<AuthentificationResult> response) {
                Log.e(TAG, "checkDeviceAuth: result code: " + response.code());
                if (response.isSuccessful() && response.code() == 200) {
                    Toast.makeText(getApplicationContext(), "response checkDeviceAuth", Toast.LENGTH_SHORT).show();
                    AuthentificationResult result = (AuthentificationResult) response.body();

                    Log.e(TAG, "DeviceAuth Info: " + response.body().toString());
                    Log.e(TAG, "DeviceAuth Info: " + result.toString());

                    String message = "";
                    switch (result.getStatus()) {
                        case 0:  checkVersion(result);  break;  // 요청성공 한 경우 수신 버전 목록에 따라 처리
                        case 1:  registerDeviceAlert(); break;  // 등록되지 않은 API TOKEN ==> 신규 디바이스 등록
                        case 2:  message = "사용가능한 유효기간이 지난 디바이스입니다.\n계속 사용하려면 관리자에 문의 하십시요."; break;    // API TOKEN 유효기간 오류
                        case 7:  message = "현재 사용할 수 없는 디바이스입니다.\n관리자에게 문의 하십시요."; break;                     // 현재 사용할수 없음, useyn='N'
                        case 8:  message = "사용 승인 대기 중입니다.\n관리자에게 문의 하십시요.\nDevice ID: " + deviceId; break;      // 등록 대기 중, useyn='Y', state='R'
                        default: message = "Device 사용권한요청 중에 알수없는 오류가 발생하였습니다."; break;
                    }
                    if (!message.equals("")) {
                        message = message + "\n오류코드(" + result.getStatus() + ")";
                        alertDialogTerminate("권한요청 오류", message);
                    }
                }
                else {
                    alertDialogTerminate("권한요청 실패", "Device 사용권한요청에 실패하였습니다.");
                }
            }

            @Override
            public void onFailure(Call<AuthentificationResult> call, Throwable t) {
                Log.e(TAG, "checkDeviceAuth: request service failed: " + t.getMessage());
                Toast.makeText(getApplicationContext(), "checkDeviceAuth failed", Toast.LENGTH_SHORT).show();
                alertDialogTerminate("권한요청 API 호출 실패", "Device 사용권한요청에 실패하였습니다.");
            }
        });
    }
    public void checkVersion(AuthentificationResult result) {

        if (result.getVersions() == null) {
            alertDialogTerminate("버전정보목록 실패", "어플리케이션 버전정보목록을 알수 없습니다.\n관리자에게 문의하십시요.");
            return;
        }

        Log.e(TAG, "checkVersion ==> versions: " + result.getVersions().toString());

        // 앱 번전 정보체크
        VersionVo version = result.getVersions().stream()
                .filter(ver -> PrefManager.APP_VERSION.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version == null) {
            alertDialogTerminate("앱버전정보 실패", "어플리케이션 버전정보를 알수 없습니다.\n관리자에게 문의하십시요.");
            return;
        }
        Log.e(TAG, PrefManager.APP_VERSION + ": " + version.getVersion());
        if (!version.getVersion().equalsIgnoreCase(PrefManager.getAppVersion(this))) {
            updateApk(version.getValue());
            return;
        }

        // WebSocket Url 확인
        version = result.getVersions().stream()
                .filter(ver -> PrefManager.WEBSOCKET_URL.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version == null) {
            alertDialogTerminate("통신정보 실패", "어플리케이션 통신정보를 알수 없습니다.\n관리자에게 문의하십시요.");
            return;
        }
        Log.e(TAG, PrefManager.WEBSOCKET_URL + ": " + version.getValue());
        PrefManager.setWebsocketUrl(this, version.getValue());

        // 노드디비 정보체크
        version = result.getVersions().stream()
                .filter(ver -> PrefManager.NODE_VERSION.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version == null) {
            alertDialogTerminate("노드버전정보 실패", "어플리케이션 노드버전정보를 알수 없습니다.\n관리자에게 문의하십시요.");
            return;
        }
        Log.e(TAG, PrefManager.NODE_VERSION + ": " + version.getVersion());
        if (!version.getVersion().equalsIgnoreCase(PrefManager.getNodeVersion(this))) {
            updateNode(version.getVersion(), version.getValue());
            return;
        }
        else {
            updateNode(version.getVersion(), version.getValue());
        }

        // Map run tilt
        int value;
        TsiNaviApplication.getMapConfig().loadConfig(this);
        version = result.getVersions().stream()
                .filter(ver -> PrefManager.MAP_RUN_TILT.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version != null) {
            value = Integer.parseInt(version.getValue());
            if (value < 0) value = 0;
            if (value > 90) value = 90;
            Log.e(TAG, PrefManager.MAP_RUN_TILT + ": " + value);
            TsiNaviApplication.getMapConfig().setRunTilt(value);
        }
        version = result.getVersions().stream()
                .filter(ver -> PrefManager.MAP_RUN_TRACKING_DISTANCE.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version != null) {
            value = Integer.parseInt(version.getValue());
            if (value < 3) value = 3;
            if (value > 30) value = 30;
            Log.e(TAG, PrefManager.MAP_RUN_TRACKING_DISTANCE + ": " + value);
            TsiNaviApplication.getMapConfig().setRunTrackingDistance(value);
        }
        version = result.getVersions().stream()
                .filter(ver -> PrefManager.MAP_RUN_DRIVE_DISTANCE.equalsIgnoreCase(ver.getItem()))
                .findFirst()
                .orElse(null);
        if (version != null) {
            value = Integer.parseInt(version.getValue());
            if (value < 5) value = 5;
            if (value > 50) value = 50;
            Log.e(TAG, PrefManager.MAP_RUN_DRIVE_DISTANCE + ": " + value);
            TsiNaviApplication.getMapConfig().setRunDriveDistance(value);
        }

        TsiNaviApplication.getMapConfig().saveConfig(this);
    }

    private void startMainActivity() {
        // MainActivity Start
        Intent intent = new Intent(getApplicationContext(), MainActivity.class);
        startActivity(intent);
        finish();
    }
    private void updateNode(String version, String fileName) {
        // 노드정보 요청
        this.tsiApiService.getNodeStatusList(this.deviceId).enqueue(new Callback<NodeStatusResult>() {
            @Override
            public void onResponse(Call<NodeStatusResult> call, retrofit2.Response<NodeStatusResult> response) {
                Log.e(TAG, "downloadNodeInfo: result code: " + response.code());
                if (response.isSuccessful() && response.code() == 200) {
                    Toast.makeText(getApplicationContext(), "downloadNodeInfo success", Toast.LENGTH_SHORT).show();
                    NodeStatusResult nodes = (NodeStatusResult)response.body();
                    List<NodeStatus> statusInfo = nodes.getStatusList();
                    Log.e(TAG, "Status Info: " + statusInfo.toString());
                    Log.e(TAG, "Status Info: " + nodes.toString());
                    Log.e(TAG, "Status Info: " + statusInfo.size());
                    if (nodes != null && nodes.getStatusList() != null) {
                        Log.e(TAG, "Status Info: " + nodes.getStatusList().size() + " EA.");

                        DbHelper.deleteDatabase(InitActivity.this);
                        DbQuery dbQuery = new DbQuery(InitActivity.this);
                        dbQuery.createDatabase();
                        dbQuery.open();

                        for (NodeStatus vo : nodes.getStatusList()) {
                            NodeVo node = NodeVo.builder()
                                    .nodeId(vo.getNodeId())
                                    .name(vo.getName())
                                    //.lat(vo.getLat())
                                    //.lng(vo.getLng())
                                    .type(vo.getType())
                                    .online(vo.getStatus() == 1)
                                    .latLng(new LatLng(vo.getLat(), vo.getLng()))
                                    .build();
                            if (dbQuery.getNodeCount(node) < 1) {
                                long result = dbQuery.insertNodeInfo(node);
                            }
                            //TsiNaviApplication.getNodeMap().put(node.getNodeId(), node);
                        }
                        dbQuery.close();
                    }
                    //Log.e(TAG, "Node Map: " + TsiNaviApplication.getNodeMap().size() + " EA.");
                    PrefManager.setNodeVersion(InitActivity.this, version);

                    startMainActivity();
                }
                else {
                    alertDialogTerminate("노드정보 다운로드 실패", "노드정보 다운로드에 실패하였습니다.");
                }
            }

            @Override
            public void onFailure(Call<NodeStatusResult> call, Throwable t) {
                alertDialogTerminate("노드정보 API 호출 실패", "노드정보 다운로드에 실패하였습니다.");
            }
        });
    }

    // 다이얼로그를 띄우고 앱을 종료한다.
    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();
    }


    // 디바이스 정보를 등록한다.
    private void registerDeviceAlert() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("디바이스 등록");
        builder.setMessage("등록되어있지 않은 디바이스 입니다.\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) {
                // 디바이스 등록 액티비티 호출
                Intent intent = new Intent(getApplicationContext(), RegisterActivity.class);
                intent.putExtra("deviceId", deviceId);
                launchResult.launch(intent);
            }
        });

        builder.setNegativeButton("취소", 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();
    }

    public void registerDeviceInfo(RegisterDevice deviceInfo) {
        Log.e(TAG, "registerDeviceInfo");
        // 디바이스 등록 요청
        tsiApiService.registerDeviceInfo(deviceInfo).enqueue(new Callback<RegisterDeviceResult>() {
            @Override
            public void onResponse(Call<RegisterDeviceResult> call, retrofit2.Response<RegisterDeviceResult> response) {
                Log.e(TAG, "register result code: " + response.code());
                if (response.isSuccessful()) {
                    alertDialogTerminate("디바이스 등록", "디바이스 정보를 등록 하였습니다.\n관리자 승인 후 앱을 이용할 수 있습니다.\n관리자 승인 후 앱을 이용하십시요.");
                }
                else {
                    alertDialogTerminate("디바이스 등록 실패", "디바이스 등록에 실패하였습니다.");
                }
            }

            @Override
            public void onFailure(Call<RegisterDeviceResult> call, Throwable t) {
                alertDialogTerminate("디바이스 등록 API 호출 실패", "디바이스 등록에 실패하였습니다.");
            }
        });
    }

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

    public static void showAlert(Context context, String title, String message, OnClickListener listener){
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle(title);
        builder.setMessage(message);
        builder.setPositiveButton("확인", listener);
        builder.setCancelable(false);
        builder.setIcon(R.mipmap.ic_launcher);
        AlertDialog dialog = builder.create();
        dialog.show();
    }

}
