package com.icing.dialer.activities

import android.Manifest
import android.app.role.RoleManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.database.Cursor
import android.os.Build
import android.os.Bundle
import android.provider.CallLog
import android.telecom.TelecomManager
import android.telephony.SubscriptionManager
import android.telephony.SubscriptionInfo
import android.util.Log
import androidx.core.content.ContextCompat
import com.icing.dialer.KeystoreHelper
import com.icing.dialer.services.CallService
import com.icing.dialer.services.MyInCallService
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : FlutterActivity() {
    private val KEYSTORE_CHANNEL = "com.example.keystore"
    private val CALLLOG_CHANNEL = "com.example.calllog"
    private val CALL_CHANNEL = "call_service"
    private val TAG = "MainActivity"
    private val REQUEST_CODE_SET_DEFAULT_DIALER = 1001
    private val REQUEST_CODE_CALL_LOG_PERMISSION = 1002
    private var pendingIncomingCall: Pair<String?, Boolean>? = null
    private var wasPhoneLocked: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "onCreate started")
        wasPhoneLocked = intent.getBooleanExtra("wasPhoneLocked", false)
        Log.d(TAG, "Was phone locked at start: $wasPhoneLocked")
        updateLockScreenFlags(intent)
        handleIncomingCallIntent(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        wasPhoneLocked = intent.getBooleanExtra("wasPhoneLocked", false)
        Log.d(TAG, "onNewIntent, wasPhoneLocked: $wasPhoneLocked")
        updateLockScreenFlags(intent)
        handleIncomingCallIntent(intent)
    }

    private fun updateLockScreenFlags(intent: Intent?) {
        val isIncomingCall = intent?.getBooleanExtra("isIncomingCall", false) ?: false
        if (isIncomingCall && wasPhoneLocked) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                setShowWhenLocked(true)
                setTurnScreenOn(true)
            } else {
                @Suppress("DEPRECATION")
                window.addFlags(
                    android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
                    android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                )
            }
            Log.d(TAG, "Enabled showWhenLocked and turnScreenOn for incoming call")
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
                setShowWhenLocked(false)
                setTurnScreenOn(false)
            } else {
                @Suppress("DEPRECATION")
                window.clearFlags(
                    android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
                    android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                )
            }
            Log.d(TAG, "Disabled showWhenLocked and turnScreenOn for normal usage")
        }
    }

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        Log.d(TAG, "Configuring Flutter engine")
        MyInCallService.channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CALL_CHANNEL)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CALL_CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "permissionsGranted" -> {
                        Log.d(TAG, "Received permissionsGranted from Flutter")
                        pendingIncomingCall?.let { (phoneNumber, showScreen) ->
                            if (showScreen) {
                                MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
                                    "phoneNumber" to phoneNumber,
                                    "wasPhoneLocked" to wasPhoneLocked
                                ))
                                pendingIncomingCall = null
                            }
                        }
                        result.success(true)
                    }                    "makeGsmCall" -> {
                        val phoneNumber = call.argument<String>("phoneNumber")
                        val simSlot = call.argument<Int>("simSlot") ?: 0
                        if (phoneNumber != null) {
                            val success = CallService.makeGsmCall(this, phoneNumber, simSlot)
                            if (success) {
                                result.success(mapOf("status" to "calling", "phoneNumber" to phoneNumber))
                            } else {
                                result.error("CALL_FAILED", "Failed to initiate call", null)
                            }
                        } else {
                            result.error("INVALID_PHONE_NUMBER", "Phone number is required", null)
                        }
                    }
                    "hangUpCall" -> {
                        val success = MyInCallService.currentCall?.let {
                            it.disconnect()
                            Log.d(TAG, "Call disconnected")
                            MyInCallService.channel?.invokeMethod("callEnded", mapOf(
                                "callId" to it.details.handle.toString(),
                                "wasPhoneLocked" to wasPhoneLocked
                            ))
                            true
                        } ?: false
                        if (success) {
                            result.success(mapOf("status" to "ended"))
                            if (wasPhoneLocked) {
                                Log.d(TAG, "Finishing and removing task after hangup, phone was locked")
                                finishAndRemoveTask()
                            }
                        } else {
                            Log.w(TAG, "No active call to hang up")
                            result.error("HANGUP_FAILED", "No active call to hang up", null)
                        }
                    }
                    "answerCall" -> {
                        val success = MyInCallService.currentCall?.let {
                            it.answer(0)
                            Log.d(TAG, "Answered call")
                            true
                        } ?: false
                        if (success) {
                            result.success(mapOf("status" to "answered"))
                        } else {
                            Log.w(TAG, "No active call to answer")
                            result.error("ANSWER_FAILED", "No active call to answer", null)
                        }
                    }
                    "callEndedFromFlutter" -> {
                        Log.d(TAG, "Call ended from Flutter, wasPhoneLocked: $wasPhoneLocked")
                        if (wasPhoneLocked) {
                            finishAndRemoveTask()
                            Log.d(TAG, "Finishing and removing task after call ended, phone was locked")
                        }
                        result.success(true)
                    }
                    "getCallState" -> {
                        val stateStr = when (MyInCallService.currentCall?.state) {
                            android.telecom.Call.STATE_ACTIVE -> "active"
                            android.telecom.Call.STATE_RINGING -> "ringing"
                            android.telecom.Call.STATE_DIALING -> "dialing"
                            android.telecom.Call.STATE_DISCONNECTED -> "disconnected"
                            android.telecom.Call.STATE_DISCONNECTING -> "disconnecting"
                            else -> "unknown"
                        }
                        Log.d(TAG, "getCallState called, returning: $stateStr")
                        result.success(stateStr)
                    }
                    "muteCall" -> {
                        val mute = call.argument<Boolean>("mute") ?: false
                        val success = MyInCallService.currentCall?.let {
                            MyInCallService.toggleMute(mute)
                        } ?: false
                        if (success) {
                            Log.d(TAG, "Mute call set to $mute")
                            result.success(mapOf("status" to "success"))
                        } else {
                            Log.w(TAG, "No active call or failed to mute")
                            result.error("MUTE_FAILED", "No active call or failed to mute", null)
                        }
                    }
                    "speakerCall" -> {
                        val speaker = call.argument<Boolean>("speaker") ?: false
                        val success = MyInCallService.currentCall?.let {
                            MyInCallService.toggleSpeaker(speaker)
                        } ?: false
                        if (success) {
                            Log.d(TAG, "Speaker call set to $speaker")
                            result.success(mapOf("status" to "success"))
                        } else {
                            Log.w(TAG, "No active call or failed to set speaker")
                            result.error("SPEAKER_FAILED", "No active call or failed to set speaker", null)
                        }
                    }
                    "isDefaultDialer" -> {
                        val isDefault = isDefaultDialer()
                        Log.d(TAG, "isDefaultDialer called, returning: $isDefault")
                        result.success(isDefault)
                    }
                    "requestDefaultDialer" -> {
                        checkAndRequestDefaultDialer()
                        result.success(true)
                    }
                    "sendDtmfTone" -> {
                        val digit = call.argument<String>("digit")
                        if (digit != null) {
                            val success = MyInCallService.sendDtmfTone(digit)
                            result.success(success)
                        } else {
                            result.error("INVALID_ARGUMENT", "Digit is null", null)
                        }
                    }
                    "isDefaultDialer" -> {
                        val isDefault = isDefaultDialer()
                        Log.d(TAG, "isDefaultDialer called, returning: $isDefault")
                        result.success(isDefault)
                    }
                    "requestDefaultDialer" -> {
                        checkAndRequestDefaultDialer()
                        result.success(true)
                    }
                    else -> result.notImplemented()
                }
            }

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, KEYSTORE_CHANNEL)
            .setMethodCallHandler { call, result ->
                KeystoreHelper(call, result).handleMethodCall()
            }

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CALLLOG_CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getCallLogs" -> {
                        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
                            val callLogs = getCallLogs()
                            result.success(callLogs)
                        } else {
                            requestPermissions(arrayOf(Manifest.permission.READ_CALL_LOG), REQUEST_CODE_CALL_LOG_PERMISSION)
                            result.error("PERMISSION_DENIED", "Call log permission not granted", null)
                        }
                    }
                    "getLatestCallLog" -> {
                        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED) {
                            val latestCallLog = getLatestCallLog()
                            result.success(latestCallLog)
                        } else {
                            result.error("PERMISSION_DENIED", "Call log permission not granted", null)
                        }
                    }
                    else -> result.notImplemented()
                }
            }
    }

    private fun isDefaultDialer(): Boolean {
        val telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
        val currentDefault = telecomManager.defaultDialerPackage
        Log.d(TAG, "Checking default dialer: current=$currentDefault, myPackage=$packageName")
        return currentDefault == packageName
    }

    private fun checkAndRequestDefaultDialer() {
        val telecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
        val currentDefault = telecomManager.defaultDialerPackage
        Log.d(TAG, "Current default dialer: $currentDefault, My package: $packageName")

        if (currentDefault != packageName) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                val roleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager
                if (roleManager.isRoleAvailable(RoleManager.ROLE_DIALER) && !roleManager.isRoleHeld(RoleManager.ROLE_DIALER)) {
                    val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER)
                    startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
                    Log.d(TAG, "Launched RoleManager intent for default dialer on API 29+")
                }
            } else {
                val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
                    .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                try {
                    startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
                    Log.d(TAG, "Launched TelecomManager intent for default dialer")
                } catch (e: Exception) {
                    Log.e(TAG, "Failed to launch default dialer prompt: ${e.message}", e)
                    launchDefaultAppsSettings()
                }
            }
        } else {
            Log.d(TAG, "Already the default dialer")
        }
    }

    private fun launchDefaultAppsSettings() {
        val settingsIntent = Intent(android.provider.Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS)
        startActivity(settingsIntent)
        Log.d(TAG, "Opened default apps settings as fallback")
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        Log.d(TAG, "onActivityResult: requestCode=$requestCode, resultCode=$resultCode, data=$data")
        if (requestCode == REQUEST_CODE_SET_DEFAULT_DIALER) {
            if (resultCode == RESULT_OK) {
                Log.d(TAG, "User accepted default dialer change")
            } else {
                Log.w(TAG, "Default dialer prompt canceled or failed (resultCode=$resultCode)")
                launchDefaultAppsSettings()
            }
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQUEST_CODE_CALL_LOG_PERMISSION) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "Call log permission granted")
                MyInCallService.channel?.invokeMethod("callLogPermissionGranted", null)
            } else {
                Log.w(TAG, "Call log permission denied")
            }
        }
    }

    private fun getCallLogs(): List<Map<String, Any?>> {
        val logsList = mutableListOf<Map<String, Any?>>()
        val cursor: Cursor? = contentResolver.query(
            CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + " DESC"
        )
        cursor?.use {
            while (it.moveToNext()) {
                val number = it.getString(it.getColumnIndexOrThrow(CallLog.Calls.NUMBER))
                val type = it.getInt(it.getColumnIndexOrThrow(CallLog.Calls.TYPE))
                val date = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DATE))
                val duration = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DURATION))
                
                // Extract subscription ID (SIM card info) if available
                var subscriptionId: Int? = null
                var simName: String? = null
                try {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                        val subIdColumnIndex = it.getColumnIndex("subscription_id")
                        if (subIdColumnIndex >= 0) {
                            subscriptionId = it.getInt(subIdColumnIndex)
                            // Get the actual SIM name
                            simName = getSimNameFromSubscriptionId(subscriptionId)
                        }
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "Failed to get subscription_id: ${e.message}")
                }

                val map = mutableMapOf<String, Any?>(
                    "number" to number,
                    "type" to type,
                    "date" to date,
                    "duration" to duration,
                    "subscription_id" to subscriptionId,
                    "sim_name" to simName
                )
                logsList.add(map)
            }
        }
        return logsList
    }

    private fun getLatestCallLog(): Map<String, Any?>? {
        val cursor: Cursor? = contentResolver.query(
            CallLog.Calls.CONTENT_URI, 
            null, 
            null, 
            null, 
            CallLog.Calls.DATE + " DESC"
        )
        cursor?.use {
            if (it.moveToNext()) {
                val number = it.getString(it.getColumnIndexOrThrow(CallLog.Calls.NUMBER))
                val type = it.getInt(it.getColumnIndexOrThrow(CallLog.Calls.TYPE))
                val date = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DATE))
                val duration = it.getLong(it.getColumnIndexOrThrow(CallLog.Calls.DURATION))
                
                // Extract subscription ID (SIM card info) if available
                var subscriptionId: Int? = null
                var simName: String? = null
                try {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                        val subIdColumnIndex = it.getColumnIndex("subscription_id")
                        if (subIdColumnIndex >= 0) {
                            subscriptionId = it.getInt(subIdColumnIndex)
                            // Get the actual SIM name
                            simName = getSimNameFromSubscriptionId(subscriptionId)
                        }
                    }
                } catch (e: Exception) {
                    Log.w(TAG, "Failed to get subscription_id: ${e.message}")
                }

                return mapOf(
                    "number" to number,
                    "type" to type,
                    "date" to date,
                    "duration" to duration,
                    "subscription_id" to subscriptionId,
                    "sim_name" to simName
                )
            }
        }
        return null
    }

    private fun getSimNameFromSubscriptionId(subscriptionId: Int?): String? {
        if (subscriptionId == null) return null
        
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
                val subscriptionManager = getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                val subscriptionInfo: SubscriptionInfo? = subscriptionManager.getActiveSubscriptionInfo(subscriptionId)
                
                return subscriptionInfo?.let { info ->
                    // Try to get display name first, fallback to carrier name, then generic name
                    when {
                        !info.displayName.isNullOrBlank() && info.displayName.toString() != info.subscriptionId.toString() -> {
                            info.displayName.toString()
                        }
                        !info.carrierName.isNullOrBlank() -> {
                            info.carrierName.toString()
                        }
                        else -> "SIM ${info.simSlotIndex + 1}"
                    }
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "Failed to get SIM name for subscription $subscriptionId: ${e.message}")
        }
        
        // Fallback to generic name
        return "SIM ${subscriptionId + 1}"
    }

    private fun handleIncomingCallIntent(intent: Intent?) {
        intent?.let {
            if (it.getBooleanExtra("isIncomingCall", false)) {
                val phoneNumber = it.getStringExtra("phoneNumber")
                val showScreen = it.getBooleanExtra("showIncomingCallScreen", false)
                Log.d(TAG, "Received incoming call intent for $phoneNumber, showScreen=$showScreen, wasPhoneLocked=$wasPhoneLocked")
                if (showScreen) {
                    if (MyInCallService.channel != null) {
                        MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
                            "phoneNumber" to phoneNumber,
                            "wasPhoneLocked" to wasPhoneLocked
                        ))
                    } else {
                        pendingIncomingCall = Pair(phoneNumber, true)
                        Log.d(TAG, "Flutter channel not ready, storing pending call: $phoneNumber")
                    }
                }
            }
        }
    }
}