package com.stand.standapp.utils

import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Environment
import android.os.Process
import android.os.StatFs
import org.json.JSONObject
import timber.log.Timber
import java.net.NetworkInterface
import java.util.Collections
import java.util.Locale

object DeviceInfoUtils {

    fun getDeviceInfoJson(context: Context): JSONObject {
        val json = JSONObject()
        val appContext = context.applicationContext

        // Base App info is typically set at the caller level, but we populate core details
        try {
            json.put("model", Build.MODEL)
            json.put("osVersion", Build.VERSION.RELEASE)

            val abis = Build.SUPPORTED_ABIS
            json.put("cpuAbi", abis.joinToString(","))

            val is64Bit = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                Process.is64Bit()
            } else {
                abis.any { it.contains("64") }
            }
            json.put("is64Bit", is64Bit)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get base device info")
        }

        // 1. Screen and display info
        try {
            val screenObj = JSONObject()
            val metrics = appContext.resources.displayMetrics
            val widthPixels = metrics.widthPixels
            val heightPixels = metrics.heightPixels
            val xdpi = metrics.xdpi
            val ydpi = metrics.ydpi

            screenObj.put("width", widthPixels)
            screenObj.put("height", heightPixels)
            screenObj.put("density", metrics.density)
            screenObj.put("densityDpi", metrics.densityDpi)

            val physicalSize = if (xdpi > 0 && ydpi > 0) {
                val widthInches = widthPixels / xdpi
                val heightInches = heightPixels / ydpi
                Math.sqrt((widthInches * widthInches + heightInches * heightInches).toDouble())
            } else {
                0.0
            }
            screenObj.put("physicalSize", Math.round(physicalSize * 10.0) / 10.0) // 1 decimal place

            json.put("screen", screenObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get screen metrics")
        }

        // 2. Hardware and manufacturer info
        try {
            val hwObj = JSONObject()
            hwObj.put("manufacturer", Build.MANUFACTURER)
            hwObj.put("brand", Build.BRAND)
            hwObj.put("hardware", Build.HARDWARE)
            hwObj.put("fingerprint", Build.FINGERPRINT)
            json.put("hardware", hwObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get hardware info")
        }

        // 3. System and Locale environment
        try {
            val sysObj = JSONObject()
            sysObj.put("sdkVersion", Build.VERSION.SDK_INT)
            sysObj.put("language", Locale.getDefault().language)
            sysObj.put("country", Locale.getDefault().country)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                sysObj.put("securityPatch", Build.VERSION.SECURITY_PATCH)
            } else {
                sysObj.put("securityPatch", "")
            }
            json.put("system", sysObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get system info")
        }

        // 4. Memory Info (RAM)
        try {
            val memObj = JSONObject()
            val actManager = appContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val memInfo = ActivityManager.MemoryInfo()
            actManager.getMemoryInfo(memInfo)
            memObj.put("totalRam", memInfo.totalMem)
            memObj.put("availRam", memInfo.availMem)
            json.put("memory", memObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get memory info")
        }

        // 5. Storage Info
        try {
            val storageObj = JSONObject()
            val path = Environment.getDataDirectory()
            val stat = StatFs(path.path)
            val blockSize = stat.blockSizeLong
            val totalBlocks = stat.blockCountLong
            val availableBlocks = stat.availableBlocksLong

            storageObj.put("totalInternal", totalBlocks * blockSize)
            storageObj.put("availInternal", availableBlocks * blockSize)
            json.put("storage", storageObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get storage info")
        }

        // 6. Network state
        try {
            val netObj = JSONObject()
            val connManager = appContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
            var networkType = "NONE"

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val activeNetwork = connManager.activeNetwork
                val capabilities = connManager.getNetworkCapabilities(activeNetwork)
                if (capabilities != null) {
                    if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                        networkType = "WIFI"
                    } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                        networkType = "CELLULAR"
                    }
                }
            } else {
                @Suppress("DEPRECATION")
                val activeNetworkInfo = connManager.activeNetworkInfo
                if (activeNetworkInfo != null && activeNetworkInfo.isConnected) {
                    if (activeNetworkInfo.type == ConnectivityManager.TYPE_WIFI) {
                        networkType = "WIFI"
                    } else if (activeNetworkInfo.type == ConnectivityManager.TYPE_MOBILE) {
                        networkType = "CELLULAR"
                    }
                }
            }
            netObj.put("type", networkType)

            var ipAddress = ""
            try {
                val interfaces = Collections.list(NetworkInterface.getNetworkInterfaces())
                for (intf in interfaces) {
                    val addrs = Collections.list(intf.inetAddresses)
                    for (addr in addrs) {
                        if (!addr.isLoopbackAddress) {
                            val sAddr = addr.hostAddress ?: continue
                            val isIPv4 = sAddr.indexOf(':') < 0
                            if (isIPv4) {
                                ipAddress = sAddr
                                break
                            }
                        }
                    }
                    if (ipAddress.isNotEmpty()) break
                }
            } catch (e: Exception) {
                Timber.tag("DeviceInfoUtils").w(e, "Failed to resolve IP address")
            }
            netObj.put("ipAddress", ipAddress)
            json.put("network", netObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get network status")
        }

        // 7. Battery status
        try {
            val batObj = JSONObject()
            val batteryStatus: Intent? = appContext.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
            val level = batteryStatus?.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, -1) ?: -1
            val scale = batteryStatus?.getIntExtra(android.os.BatteryManager.EXTRA_SCALE, -1) ?: -1
            val batteryPct = if (level >= 0 && scale > 0) (level * 100 / scale.toFloat()).toInt() else -1
            batObj.put("level", batteryPct)

            val status = batteryStatus?.getIntExtra(android.os.BatteryManager.EXTRA_STATUS, -1) ?: -1
            val statusString = when (status) {
                android.os.BatteryManager.BATTERY_STATUS_CHARGING -> "charging"
                android.os.BatteryManager.BATTERY_STATUS_DISCHARGING -> "discharging"
                android.os.BatteryManager.BATTERY_STATUS_FULL -> "full"
                android.os.BatteryManager.BATTERY_STATUS_NOT_CHARGING -> "not_charging"
                else -> "unknown"
            }
            batObj.put("status", statusString)

            val chargePlug = batteryStatus?.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) ?: -1
            val plugString = when (chargePlug) {
                android.os.BatteryManager.BATTERY_PLUGGED_AC -> "ac"
                android.os.BatteryManager.BATTERY_PLUGGED_USB -> "usb"
                android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS -> "wireless"
                else -> "none"
            }
            batObj.put("plugged", plugString)
            json.put("battery", batObj)
        } catch (e: Exception) {
            Timber.tag("DeviceInfoUtils").e(e, "Failed to get battery info")
        }

        return json
    }
}