// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.data.crash

import android.content.Context
import com.coldboreballisticsllc.scopedope.BuildConfig
import com.coldboreballisticsllc.scopedope.ballistics.CrashReporting
import dagger.hilt.android.qualifiers.ApplicationContext
import io.sentry.Sentry
import io.sentry.SentryLevel
import io.sentry.android.core.SentryAndroid
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Sentry-backed [CrashReportingController] (SPEC §16.1).
 *
 * **Opt-in, OFF by default.** Sentry auto-init is disabled in the manifest
 * (`io.sentry.auto-init=false`); this class is the only thing that ever starts the SDK,
 * and only via [enable], which the app calls solely after the user consents.
 *
 * **Hardening (Sentry_Security_Review.md §5.1):**
 * - DSN comes from [BuildConfig.SENTRY_DSN] (injected from Key Vault). Empty DSN → permanent no-op.
 * - `sendDefaultPii = false` — no IP/PII auto-attached.
 * - No `User` is ever set; on init any user context is explicitly cleared.
 * - A `beforeSend` hook scrubs network identity (server name) and drops Session-Replay events,
 *   belt-and-suspenders behind the dependency exclusions in build.gradle.kts.
 * - Breadcrumbs forwarded from shared code are category labels only (no user/ballistic content).
 */
@Singleton
class SentryCrashReporter @Inject constructor(
    @ApplicationContext private val context: Context,
) : CrashReportingController {

    @Volatile
    private var enabled = false

    private val dsn: String = BuildConfig.SENTRY_DSN

    override val isEnabled: Boolean get() = enabled

    override fun enable() {
        if (enabled) return
        if (dsn.isBlank()) return  // no DSN configured → reporting stays disabled

        SentryAndroid.init(context) { options ->
            options.dsn = dsn

            // ── Privacy hardening ──────────────────────────────────────────────
            options.isSendDefaultPii = false          // no IP / PII auto-attached
            options.isEnableUserInteractionBreadcrumbs = false
            options.isEnableUserInteractionTracing = false
            options.isAttachScreenshot = false        // never capture the screen
            options.isAttachViewHierarchy = false      // never capture the view tree
            options.tracesSampleRate = 0.0             // no performance tracing
            options.sessionReplay.onErrorSampleRate = 0.0
            options.sessionReplay.sessionSampleRate = 0.0
            options.environment =
                if (BuildConfig.DEBUG) "debug" else "release"
            options.release = "scopedope-android@${BuildConfig.VERSION_NAME}"

            // ── beforeSend: final scrub — drop anything outside the permitted payload ──
            options.beforeSend = io.sentry.SentryOptions.BeforeSendCallback { event, _ ->
                // Strip any network/host identity that could localize the user.
                event.serverName = null
                event.user = null
                event.request = null
                event
            }
        }

        // Defensively ensure no user identity is ever attached to the scope.
        Sentry.configureScope { scope -> scope.user = null }

        // Route shared-engine reporting through this reporter.
        CrashReporting.install(this)
        enabled = true
    }

    override fun disable() {
        if (!enabled) return
        // Tear down the SDK so nothing further is transmitted this session.
        Sentry.close()
        CrashReporting.install(com.coldboreballisticsllc.scopedope.ballistics.NoOpCrashReporter)
        enabled = false
    }

    // ── CrashReporter (shared contract) ───────────────────────────────────────

    override fun recordHandledException(throwable: Throwable) {
        if (!enabled) return
        Sentry.captureException(throwable)
    }

    override fun recordBreadcrumb(message: String) {
        if (!enabled) return
        Sentry.addBreadcrumb(message, "app")
    }
}
