package com.bytelyst.platform

import android.content.Context
import android.graphics.Bitmap
import android.view.View
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.ByteArrayOutputStream
import java.util.Locale
import java.util.concurrent.TimeUnit

/**
 * Feedback client for submitting user feedback with optional screenshots.
 *
 * TODO-3: Full implementation for Android
 *
 * Flow:
 * 1. Capture screenshot (optional)
 * 2. Get SAS URL for upload
 * 3. Upload screenshot to blob storage
 * 4. Submit feedback with metadata
 */
class BLFeedbackClient(
    private val config: BLPlatformConfig,
    private val tokenProvider: () -> String? = { null },
) {
    enum class FeedbackType {
        BUG, FEATURE, PRAISE, OTHER
    }

    enum class ScreenshotFormat {
        PNG, JPEG, WEBP
    }

    data class DeviceContext(
        val osVersion: String,
        val appVersion: String,
        val deviceModel: String,
        val screenResolution: String,
        val locale: String,
    ) {
        companion object {
            fun fromContext(context: Context): DeviceContext {
                val displayMetrics = context.resources.displayMetrics
                return DeviceContext(
                    osVersion = android.os.Build.VERSION.RELEASE,
                    appVersion = context.packageManager.getPackageInfo(
                        context.packageName, 0
                    ).versionName ?: "unknown",
                    deviceModel = "${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}",
                    screenResolution = "${displayMetrics.widthPixels}x${displayMetrics.heightPixels}",
                    locale = Locale.getDefault().toString(),
                )
            }
        }
    }

    @Serializable
    data class SasResponse(
        val blobPath: String,
        val uploadUrl: String,
        val expiresIn: Int,
        val maxSizeBytes: Int,
    )

    @Serializable
    data class FeedbackResponse(
        val id: String,
        val productId: String,
        val userId: String,
        val type: String,
        val title: String,
        val status: String,
        val createdAt: String,
        val screenshotBlobPath: String? = null,
    )

    data class FeedbackParams(
        val type: FeedbackType,
        val title: String,
        val body: String? = null,
        val screen: String? = null,
        val rating: Int? = null,
        val screenshot: Pair<ByteArray, ScreenshotFormat>? = null,
        val deviceContext: DeviceContext? = null,
    )

    private val json = Json { ignoreUnknownKeys = true }
    private val platformClient = BLPlatformClient(config, tokenProvider)
    private val uploadClient = OkHttpClient.Builder()
        .connectTimeout(60, TimeUnit.SECONDS)
        .writeTimeout(120, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build()

    /**
     * Submit feedback with optional screenshot.
     *
     * TODO-3: Full implementation
     */
    suspend fun submitFeedback(params: FeedbackParams): FeedbackResponse? = withContext(Dispatchers.IO) {
        try {
            // Step 1: Handle screenshot upload if provided
            var screenshotMeta: Triple<String, String, Int>? = null
            params.screenshot?.let { (data, format) ->
                val contentType = when (format) {
                    ScreenshotFormat.PNG -> "image/png"
                    ScreenshotFormat.JPEG -> "image/jpeg"
                    ScreenshotFormat.WEBP -> "image/webp"
                }

                // Get SAS URL
                val sas = generateSASUrl(contentType) ?: return@withContext null

                // Upload screenshot
                val uploaded = uploadScreenshot(data, sas.uploadUrl, contentType)
                if (!uploaded) return@withContext null

                screenshotMeta = Triple(sas.blobPath, contentType, data.size)
            }

            // Step 2: Submit feedback
            val body = buildMap {
                put("type", params.type.name.lowercase())
                put("title", params.title)
                params.body?.let { put("body", it) }
                params.screen?.let { put("screen", it) }
                params.rating?.let { put("rating", it) }
                screenshotMeta?.let { (path, type, size) ->
                    put("screenshotBlobPath", path)
                    put("screenshotContentType", type)
                    put("screenshotSizeBytes", size)
                }
                params.deviceContext?.let { ctx ->
                    put("deviceContext", mapOf(
                        "osVersion" to ctx.osVersion,
                        "appVersion" to ctx.appVersion,
                        "deviceModel" to ctx.deviceModel,
                        "screenResolution" to ctx.screenResolution,
                        "locale" to ctx.locale,
                    ))
                }
            }

            // TODO-3: Implement actual API call
            throw NotImplementedError(
                "submitFeedback API call not yet implemented. " +
                "Use platformClient.request(\"POST\", \"/api/feedback\", jsonBody)"
            )
        } catch (_: Exception) {
            null
        }
    }

    /**
     * Capture screenshot and submit feedback in one operation.
     *
     * TODO-3: Full implementation using MediaProjection or View.draw()
     */
    suspend fun captureAndSubmit(
        context: Context,
        type: FeedbackType,
        title: String,
        body: String? = null,
    ): FeedbackResponse? {
        throw NotImplementedError(
            "captureAndSubmit not yet implemented.\n\n" +
            "To implement:\n" +
            "1. Option A - MediaProjection API (requires permission):\n" +
            "   - Request MediaProjection permission\n" +
            "   - Use MediaProjection.createVirtualDisplay()\n" +
            "   - Capture ImageReader frame\n\n" +
            "2. Option B - View.draw() (limited to app window):\n" +
            "   - val view = window.decorView.rootView\n" +
            "   - val bitmap = Bitmap.createBitmap(view.width, view.height)\n" +
            "   - val canvas = Canvas(bitmap)\n" +
            "   - view.draw(canvas)\n\n" +
            "3. Convert Bitmap to ByteArray\n" +
            "4. Call submitFeedback with screenshot"
        )
    }

    /**
     * Capture current screen as Bitmap.
     *
     * TODO-3: Full implementation
     */
    fun captureScreen(): Bitmap {
        throw NotImplementedError(
            "captureScreen requires MediaProjection API. " +
            "See: https://developer.android.com/reference/android/media/projection/MediaProjection"
        )
    }

    /**
     * Capture specific View as Bitmap.
     *
     * TODO-3: Full implementation
     */
    fun captureView(view: View): Bitmap {
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val canvas = android.graphics.Canvas(bitmap)
        view.draw(canvas)
        return bitmap
    }

    /**
     * Convert Bitmap to PNG ByteArray.
     */
    fun bitmapToBytes(bitmap: Bitmap, format: ScreenshotFormat = ScreenshotFormat.PNG): ByteArray {
        val androidFormat = when (format) {
            ScreenshotFormat.PNG -> Bitmap.CompressFormat.PNG
            ScreenshotFormat.JPEG -> Bitmap.CompressFormat.JPEG
            ScreenshotFormat.WEBP -> Bitmap.CompressFormat.WEBP_LOSSY
        }
        val stream = ByteArrayOutputStream()
        bitmap.compress(androidFormat, 90, stream)
        return stream.toByteArray()
    }

    // MARK: - Private

    private suspend fun generateSASUrl(contentType: String): SasResponse? = withContext(Dispatchers.IO) {
        try {
            val body = json.encodeToString(
                MapSerializer(String.serializer(), String.serializer()),
                mapOf("contentType" to contentType),
            )
            val response = platformClient.request("POST", "/api/feedback/sas", body)
            json.decodeFromString(SasResponse.serializer(), response)
        } catch (_: Exception) {
            null
        }
    }

    private suspend fun uploadScreenshot(
        data: ByteArray,
        sasUrl: String,
        contentType: String,
    ): Boolean = withContext(Dispatchers.IO) {
        try {
            val request = Request.Builder()
                .url(sasUrl)
                .put(data.toRequestBody(contentType.toMediaType()))
                .header("x-ms-blob-type", "BlockBlob")
                .header("x-ms-blob-content-type", contentType)
                .build()

            uploadClient.newCall(request).execute().use { response ->
                response.isSuccessful
            }
        } catch (_: Exception) {
            false
        }
    }
}
