package com.pedshub.scribe;

import android.Manifest;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.provider.MediaStore;
import android.util.Base64;
import android.view.WindowManager;
import android.webkit.CookieManager;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebViewClient;
import android.webkit.WebView;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.getcapacitor.BridgeActivity;

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

public class MainActivity extends BridgeActivity {

    private static final int MIC_PERMISSION_CODE = 1001;
    private PermissionRequest pendingPermissionRequest;
    private WebView printWebView;

    // True between startForegroundService() and stopForegroundService(), i.e.
    // while the web app has an active MediaRecorder. Drives the keep-screen-on
    // flag and the timer-throttling workaround below.
    private volatile boolean recordingActive = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Request mic permission upfront
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{ Manifest.permission.RECORD_AUDIO }, MIC_PERMISSION_CODE);
        }

        // Allow the Cloudflare Turnstile iframe to use storage.
        setupThirdPartyCookies();

        // Setup WebView mic permission granting
        setupWebViewPermissions();

        // Register JS interface for foreground service control
        setupRecordingBridge();

        // Register JS interface for Android's print / Save as PDF flow.
        setupPrintBridge();

        // Register JS interface for saving generated visuals to Photos.
        setupFileBridge();
    }

    // ── Recording Lifecycle ────────────────────────────────────
    //
    // Recording happens in the WebView (MediaRecorder), not in native code,
    // so keeping the foreground service alive is necessary but not sufficient
    // — the WebView also has to keep executing JS. Two things protect that:
    //
    //  1. FLAG_KEEP_SCREEN_ON while recording, so the device does not
    //     auto-lock mid-encounter. This is the case that actually bites
    //     clinicians: a long pause in conversation and the screen times out.
    //
    //  2. resumeTimers() if the activity is paused anyway (user presses the
    //     power button, or a call comes in). Chromium throttles timers hard
    //     for hidden WebViews, which starves MediaRecorder's chunk delivery.
    //     Capacitor never calls webView.onPause(), so the WebView itself is
    //     still live — it is only the timers that need rescuing.
    //
    // Note resumeTimers()/pauseTimers() are process-global in WebView, not
    // per-instance; calling resume here is safe because this app has no other
    // WebView that wants throttling (printWebView is transient).

    void setKeepScreenOn(final boolean on) {
        runOnUiThread(() -> {
            if (on) {
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
            } else {
                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
            }
        });
    }

    void setRecordingActive(boolean active) {
        recordingActive = active;
        setKeepScreenOn(active);
    }

    // NB: BridgeActivity declares these public — narrowing to protected would
    // not compile.
    @Override
    public void onPause() {
        super.onPause();
        if (recordingActive && this.bridge != null && this.bridge.getWebView() != null) {
            this.bridge.getWebView().resumeTimers();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (this.bridge != null && this.bridge.getWebView() != null) {
            this.bridge.getWebView().resumeTimers();
        }
    }

    // ── Third-Party Cookies ────────────────────────────────────
    //
    // Android WebView blocks third-party cookies by default (unlike Chrome,
    // which still allows them for now). Cloudflare Turnstile runs inside a
    // cross-origin iframe from challenges.cloudflare.com and needs its own
    // storage to run and persist a challenge — without this the widget
    // silently stalls or errors and never emits a token, so registration and
    // password reset are impossible from inside the app.
    //
    // This is scoped to our own WebView, which only ever loads the PedScribe
    // origin (see allowNavigation in capacitor.config.json), so it is not a
    // general relaxation of the app's cookie policy.

    private void setupThirdPartyCookies() {
        WebView webView = this.bridge.getWebView();
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        cookieManager.setAcceptThirdPartyCookies(webView, true);
    }

    // ── WebView Microphone Permission ──────────────────────────

    private void setupWebViewPermissions() {
        WebView webView = this.bridge.getWebView();
        final MainActivity activity = this;

        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onPermissionRequest(final PermissionRequest request) {
                if (ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)
                        == PackageManager.PERMISSION_GRANTED) {
                    activity.runOnUiThread(() -> request.grant(request.getResources()));
                } else {
                    pendingPermissionRequest = request;
                    ActivityCompat.requestPermissions(activity,
                            new String[]{ Manifest.permission.RECORD_AUDIO }, MIC_PERMISSION_CODE);
                }
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if (requestCode == MIC_PERMISSION_CODE && pendingPermissionRequest != null) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                final PermissionRequest req = pendingPermissionRequest;
                runOnUiThread(() -> req.grant(req.getResources()));
            } else {
                pendingPermissionRequest.deny();
            }
            pendingPermissionRequest = null;
        }
    }

    // ── Background Recording Service Bridge ───────────────────

    private void setupRecordingBridge() {
        WebView webView = this.bridge.getWebView();
        webView.addJavascriptInterface(new RecordingBridge(this), "NativeRecording");
    }

    private void setupPrintBridge() {
        WebView webView = this.bridge.getWebView();
        webView.addJavascriptInterface(new PrintBridge(this), "NativePrint");
    }

    private void setupFileBridge() {
        WebView webView = this.bridge.getWebView();
        webView.addJavascriptInterface(new FileBridge(this), "NativeFiles");
    }

    public static class RecordingBridge {
        private final MainActivity activity;

        RecordingBridge(MainActivity activity) {
            this.activity = activity;
        }

        @android.webkit.JavascriptInterface
        public void startForegroundService() {
            Intent intent = new Intent(activity, AudioRecordingService.class);
            ContextCompat.startForegroundService(activity, intent);
            activity.setRecordingActive(true);
        }

        @android.webkit.JavascriptInterface
        public void stopForegroundService() {
            Intent intent = new Intent(activity, AudioRecordingService.class);
            intent.setAction(AudioRecordingService.ACTION_STOP);
            activity.startService(intent);
            activity.setRecordingActive(false);
        }

        // Standalone keep-awake, exposed so the web app can hold the screen on
        // for non-recording work too. window.nativeKeepAwake() previously
        // called Capacitor's KeepAwake plugin, which is not installed in this
        // project — so it silently did nothing and the screen slept during
        // recordings.
        @android.webkit.JavascriptInterface
        public void keepAwake(boolean on) {
            activity.setKeepScreenOn(on);
        }
    }

    public static class PrintBridge {
        private final MainActivity activity;

        PrintBridge(MainActivity activity) {
            this.activity = activity;
        }

        @android.webkit.JavascriptInterface
        public void printHtml(String title, String base64Html) {
            activity.runOnUiThread(() -> activity.printHtmlFromBase64(title, base64Html));
        }
    }

    public static class FileBridge {
        private final MainActivity activity;

        FileBridge(MainActivity activity) {
            this.activity = activity;
        }

        @android.webkit.JavascriptInterface
        public String saveImage(String filename, String base64Png) {
            return activity.saveImageToPictures(filename, base64Png);
        }
    }

    private void printHtmlFromBase64(String title, String base64Html) {
        try {
            byte[] decoded = Base64.decode(base64Html, Base64.DEFAULT);
            String html = new String(decoded, java.nio.charset.StandardCharsets.UTF_8);
            printWebView = new WebView(this);
            printWebView.setWebViewClient(new WebViewClient() {
                @Override
                public void onPageFinished(WebView view, String url) {
                    PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
                    PrintDocumentAdapter adapter = view.createPrintDocumentAdapter(title != null && !title.isEmpty() ? title : "Clinical Assistant Export");
                    printManager.print(title != null && !title.isEmpty() ? title : "Clinical Assistant Export", adapter, new PrintAttributes.Builder().build());
                }
            });
            printWebView.loadDataWithBaseURL(null, html, "text/html", "UTF-8", null);
        } catch (Exception e) {
            android.util.Log.e("PedScribe", "Native print failed", e);
        }
    }

    private String saveImageToPictures(String filename, String base64Png) {
        String safeName = sanitizeFilename(filename, "clinical-visual.png");
        try {
            byte[] imageBytes = Base64.decode(base64Png, Base64.DEFAULT);
            Uri uri;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ContentResolver resolver = getContentResolver();
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DISPLAY_NAME, safeName);
                values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
                values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/PedScribe");
                values.put(MediaStore.Images.Media.IS_PENDING, 1);
                uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                if (uri == null) return "error:Could not create image file";
                try (OutputStream out = resolver.openOutputStream(uri)) {
                    if (out == null) return "error:Could not open image file";
                    out.write(imageBytes);
                }
                values.clear();
                values.put(MediaStore.Images.Media.IS_PENDING, 0);
                resolver.update(uri, values, null, null);
            } else {
                File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "PedScribe");
                if (!dir.exists() && !dir.mkdirs()) return "error:Could not create Pictures/PedScribe";
                File file = new File(dir, safeName);
                try (OutputStream out = new FileOutputStream(file)) {
                    out.write(imageBytes);
                }
                uri = Uri.fromFile(file);
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            }
            return "saved:" + uri.toString();
        } catch (Exception e) {
            android.util.Log.e("PedScribe", "Native image save failed", e);
            return "error:" + (e.getMessage() != null ? e.getMessage() : "Image save failed");
        }
    }

    private String sanitizeFilename(String filename, String fallback) {
        String value = filename != null ? filename : fallback;
        value = value.replaceAll("[^A-Za-z0-9._-]", "-");
        if (value.length() == 0) value = fallback;
        if (!value.toLowerCase(java.util.Locale.US).endsWith(".png")) value = value + ".png";
        return value;
    }
}
