package com.dewemoji.app;

import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
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.util.Log;
import android.webkit.WebView;
import android.widget.Toast;

import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;

import com.dewemoji.app.plugins.DewemojiOverlayPlugin;
import com.getcapacitor.BridgeActivity;

import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class MainActivity extends BridgeActivity {
    private static final String TAG = "DewemojiUpdater";
    private static final String VERSION_URL = "https://dewemoji.com/downloads/version.json";
    private static final String EXTRA_OPENED_FROM_BUBBLE = "dewemoji_opened_from_bubble";
    private static final int CONNECT_TIMEOUT_MS = 10000;
    private static final int READ_TIMEOUT_MS = 15000;
    private boolean openedFromBubble = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        registerPlugin(DewemojiOverlayPlugin.class);
        super.onCreate(savedInstanceState);
        openedFromBubble = wasOpenedFromBubble(getIntent());
        applySystemBarMode();
        getWindow().getDecorView().post(this::applySystemBarMode);
        checkForUpdates(false);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        openedFromBubble = wasOpenedFromBubble(intent);
        applySystemBarMode();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus) {
            applySystemBarMode();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        applySystemBarMode();
        getWindow().getDecorView().post(this::applySystemBarMode);
    }

    @Override
    public void onBackPressed() {
        WebView webView = getBridge() != null ? getBridge().getWebView() : null;
        if (webView == null) {
            super.onBackPressed();
            return;
        }

        try {
            webView.evaluateJavascript(
                "(function(){try{return (window.dewemojiHandleAndroidBack && window.dewemojiHandleAndroidBack()) ? '1' : '0';}catch(e){return '0';}})();",
                value -> {
                    boolean handled = value != null && value.contains("1");
                    if (handled) {
                        return;
                    }
                    if (webView.canGoBack()) {
                        webView.goBack();
                        return;
                    }
                    MainActivity.super.onBackPressed();
                }
            );
        } catch (Exception ex) {
            if (webView.canGoBack()) {
                webView.goBack();
            } else {
                super.onBackPressed();
            }
        }
    }

    private boolean wasOpenedFromBubble(Intent intent) {
        return intent != null && intent.getBooleanExtra(EXTRA_OPENED_FROM_BUBBLE, false);
    }

    private void applySystemBarMode() {
        // Fallback to non-immersive mode whenever the overlay bubble service is active;
        // some launch paths may not preserve the intent extra on all OEMs.
        if (openedFromBubble || OverlayBubbleService.isRunning()) {
            showSystemBars();
            return;
        }
        hideSystemBars();
    }

    private void hideSystemBars() {
        WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
        WindowInsetsControllerCompat controller =
            new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());
        controller.hide(WindowInsetsCompat.Type.statusBars() | WindowInsetsCompat.Type.navigationBars());
        controller.setSystemBarsBehavior(
            WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
        );
    }

    private void showSystemBars() {
        WindowCompat.setDecorFitsSystemWindows(getWindow(), true);
        WindowInsetsControllerCompat controller =
            new WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());
        controller.show(WindowInsetsCompat.Type.statusBars() | WindowInsetsCompat.Type.navigationBars());
    }

    private void checkForUpdates(boolean manual) {
        new Thread(() -> {
            try {
                UpdateMetadata metadata = fetchVersionMetadata();
                if (metadata == null) {
                    return;
                }

                long installedVersion = getInstalledVersionCode();
                if (metadata.versionCode <= installedVersion) {
                    if (manual) {
                        runOnUiThread(() ->
                            Toast.makeText(this, "Dewemoji is up to date", Toast.LENGTH_SHORT).show()
                        );
                    }
                    return;
                }

                runOnUiThread(() -> showUpdateDialog(metadata));
            } catch (Exception ex) {
                Log.w(TAG, "Update check failed", ex);
                if (manual) {
                    runOnUiThread(() ->
                        Toast.makeText(this, "Update check failed", Toast.LENGTH_SHORT).show()
                    );
                }
            }
        }).start();
    }

    private UpdateMetadata fetchVersionMetadata() throws Exception {
        HttpURLConnection conn = (HttpURLConnection) new URL(VERSION_URL).openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(CONNECT_TIMEOUT_MS);
        conn.setReadTimeout(READ_TIMEOUT_MS);
        conn.setRequestProperty("Accept", "application/json");

        int code = conn.getResponseCode();
        if (code < 200 || code >= 300) {
            throw new IllegalStateException("Unexpected status " + code);
        }

        try (InputStream in = new BufferedInputStream(conn.getInputStream());
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[8192];
            int read;
            while ((read = in.read(buffer)) != -1) {
                out.write(buffer, 0, read);
            }
            String json = out.toString(StandardCharsets.UTF_8.name());
            JSONObject obj = new JSONObject(json);
            return UpdateMetadata.fromJson(obj);
        } finally {
            conn.disconnect();
        }
    }

    private long getInstalledVersionCode() throws Exception {
        PackageManager packageManager = getPackageManager();
        PackageInfo info = packageManager.getPackageInfo(getPackageName(), 0);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            return info.getLongVersionCode();
        }
        return info.versionCode;
    }

    private void showUpdateDialog(UpdateMetadata metadata) {
        StringBuilder message = new StringBuilder();
        message.append("New version ").append(metadata.versionName).append(" is available.");
        if (!metadata.notes.isEmpty()) {
            message.append("\n\n").append(metadata.notes);
        }

        AlertDialog.Builder builder = new AlertDialog.Builder(this)
            .setTitle("Update Dewemoji")
            .setMessage(message.toString())
            .setPositiveButton("Download", (dialog, which) -> openApkDownloadPage(metadata.apkUrl))
            .setCancelable(!metadata.force);

        if (!metadata.force) {
            builder.setNegativeButton("Later", null);
        }

        builder.show();
    }

    private void openApkDownloadPage(String apkUrl) {
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(apkUrl));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        } catch (ActivityNotFoundException ex) {
            Toast.makeText(this, "No browser found", Toast.LENGTH_SHORT).show();
        } catch (Exception ex) {
            Log.e(TAG, "Failed to open APK URL", ex);
            Toast.makeText(this, "Cannot open update URL", Toast.LENGTH_SHORT).show();
        }
    }

    private static class UpdateMetadata {
        final String versionName;
        final long versionCode;
        final String apkUrl;
        final String notes;
        final boolean force;

        private UpdateMetadata(
            String versionName,
            long versionCode,
            String apkUrl,
            String notes,
            boolean force
        ) {
            this.versionName = versionName;
            this.versionCode = versionCode;
            this.apkUrl = apkUrl;
            this.notes = notes;
            this.force = force;
        }

        static UpdateMetadata fromJson(JSONObject obj) {
            String versionName = obj.optString("versionName", "");
            long versionCode = obj.optLong("versionCode", 0);
            String apkUrl = obj.optString("apkUrl", "");
            String notes = obj.optString("notes", "");
            boolean force = obj.optBoolean("force", false);

            if (versionName.isEmpty() || versionCode <= 0 || apkUrl.isEmpty()) {
                throw new IllegalStateException("Invalid version metadata payload");
            }

            return new UpdateMetadata(versionName, versionCode, apkUrl, notes, force);
        }
    }
}
