package com.example.godeye.ui.viewmodels

import android.app.Application
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.example.godeye.managers.PermissionManager
import com.example.godeye.models.*
import com.example.godeye.services.CameraService
import com.example.godeye.services.SocketService
import com.example.godeye.utils.Constants
import com.example.godeye.utils.Logger
import com.example.godeye.utils.getPreferences
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

/**
 * ViewModel для главного экрана приложения
 */
class MainViewModel(application: Application) : AndroidViewModel(application) {

    private val context = getApplication<Application>()
    private val permissionManager = PermissionManager(context)

    // Сервисы
    private var socketService: SocketService? = null
    private var cameraService: CameraService? = null
    private var socketServiceBound = false
    private var cameraServiceBound = false

    // UI State
    private val _uiState = MutableStateFlow(MainScreenState())
    val uiState: StateFlow<MainScreenState> = _uiState.asStateFlow()

    // События для UI
    private val _events = MutableSharedFlow<UiEvent>()
    val events: SharedFlow<UiEvent> = _events.asSharedFlow()

    init {
        loadSavedSettings()
        // startServices() убран отсюда
    }

    /**
     * Загрузить сохраненные настройки
     */
    private fun loadSavedSettings() {
        val prefs = context.getPreferences()
        val serverUrl = prefs.getString(Constants.PreferenceKeys.SERVER_URL, Constants.DEFAULT_SERVER_URL) ?: Constants.DEFAULT_SERVER_URL
        val deviceId = prefs.getString(Constants.PreferenceKeys.DEVICE_ID, "") ?: ""

        _uiState.value = _uiState.value.copy(
            serverUrl = serverUrl,
            deviceId = deviceId
        )
    }

    /**
     * Запустить сервисы (вызывать из MainActivity после проверки разрешений)
     */
    fun startServices() {
        // Запуск SocketService
        val socketIntent = Intent(context, SocketService::class.java)
        context.startForegroundService(socketIntent)
        context.bindService(socketIntent, socketConnection, Context.BIND_AUTO_CREATE)

        // Запуск CameraService
        val cameraIntent = Intent(context, CameraService::class.java)
        context.startForegroundService(cameraIntent)
        context.bindService(cameraIntent, cameraConnection, Context.BIND_AUTO_CREATE)
    }

    /**
     * ServiceConnection для SocketService
     */
    private val socketConnection = object : ServiceConnection {
        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            val binder = service as SocketService.LocalBinder
            socketService = binder.getService()
            socketServiceBound = true

            Logger.d("SocketService connected")
            observeSocketService()
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            socketServiceBound = false
            socketService = null
            Logger.d("SocketService disconnected")
        }
    }

    /**
     * ServiceConnection для CameraService
     */
    private val cameraConnection = object : ServiceConnection {
        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            val binder = service as CameraService.LocalBinder
            cameraService = binder.getService()
            cameraServiceBound = true

            Logger.d("CameraService connected")
            observeCameraService()
            setupCameraServiceCallbacks()
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            cameraServiceBound = false
            cameraService = null
            Logger.d("CameraService disconnected")
        }
    }

    /**
     * Наблюдать за состоянием SocketService
     */
    private fun observeSocketService() {
        val service = socketService ?: return

        viewModelScope.launch {
            service.connectionState.collect { state ->
                _uiState.value = _uiState.value.copy(connectionState = state)
            }
        }

        viewModelScope.launch {
            service.deviceId.collect { deviceId ->
                _uiState.value = _uiState.value.copy(deviceId = deviceId)
            }
        }

        viewModelScope.launch {
            service.error.collect { error ->
                error?.let {
                    _uiState.value = _uiState.value.copy(error = it)
                    _events.emit(UiEvent.ShowError(it))
                }
            }
        }

        viewModelScope.launch {
            service.cameraRequest.collect { request ->
                request?.let {
                    _uiState.value = _uiState.value.copy(showCameraRequest = it)
                    _events.emit(UiEvent.ShowCameraRequestDialog(it))
                }
            }
        }

        viewModelScope.launch {
            service.webrtcOffer.collect { offer ->
                offer?.let {
                    handleWebRTCOffer(it)
                    service.clearWebRTCOffer()
                }
            }
        }

        viewModelScope.launch {
            service.webrtcIceCandidate.collect { candidate ->
                candidate?.let {
                    handleWebRTCIceCandidate(it)
                }
            }
        }

        viewModelScope.launch {
            service.cameraSwitchRequest.collect { request ->
                request?.let { (sessionId, cameraType) ->
                    handleCameraSwitch(sessionId, cameraType)
                }
            }
        }

        viewModelScope.launch {
            service.sessionDisconnect.collect { sessionId ->
                sessionId?.let {
                    handleSessionDisconnect(it)
                }
            }
        }
    }

    /**
     * Наблюдать за состоянием CameraService
     */
    private fun observeCameraService() {
        val service = cameraService ?: return

        viewModelScope.launch {
            service.getSessionManager().activeSessions.collect { sessions ->
                _uiState.value = _uiState.value.copy(activeSessions = sessions)
            }
        }

        viewModelScope.launch {
            service.error.collect { error ->
                error?.let {
                    _uiState.value = _uiState.value.copy(error = it)
                    _events.emit(UiEvent.ShowError(it))
                }
            }
        }
    }

    /**
     * Настроить callbacks для CameraService
     */
    private fun setupCameraServiceCallbacks() {
        cameraService?.setWebRTCCallbacks(
            onOfferCreated = { sessionId, offer ->
                // WebRTC offer создан, но в нашем случае мы получаем offer от оператора
                Logger.d("WebRTC offer created for session: $sessionId")
            },
            onIceCandidateCreated = { sessionId, candidate, sdpMid, sdpMLineIndex ->
                socketService?.sendIceCandidate(sessionId, candidate, sdpMid, sdpMLineIndex)
            }
        )
    }

    /**
     * Подключиться к серверу
     */
    fun connect() {
        if (!permissionManager.hasCriticalPermissions()) {
            _events.tryEmit(UiEvent.RequestPermissions)
            return
        }

        val serverUrl = _uiState.value.serverUrl
        if (serverUrl.isBlank()) {
            _events.tryEmit(UiEvent.ShowError(AppError.SocketError("Введите URL сервера")))
            return
        }

        // Сохраняем URL сервера
        context.getPreferences().edit()
            .putString(Constants.PreferenceKeys.SERVER_URL, serverUrl)
            .apply()

        _uiState.value = _uiState.value.copy(isLoading = true)
        socketService?.connect(serverUrl)
    }

    /**
     * Отключиться от сервера
     */
    fun disconnect() {
        _uiState.value = _uiState.value.copy(isLoading = true)
        socketService?.disconnect()
        cameraService?.endAllSessions()
    }

    /**
     * Обновить URL сервера
     */
    fun updateServerUrl(url: String) {
        _uiState.value = _uiState.value.copy(serverUrl = url)
    }

    /**
     * Ответить на запрос камеры
     */
    fun respondToCameraRequest(sessionId: String, accepted: Boolean, reason: String? = null) {
        socketService?.sendCameraResponse(sessionId, accepted, reason)

        if (accepted) {
            // Получаем информацию о запросе
            val request = _uiState.value.showCameraRequest
            if (request != null && request.sessionId == sessionId) {
                // Начинаем камера сессию
                cameraService?.startCameraSession(sessionId, request.operatorId, request.cameraType)
            }
        }

        // Очищаем запрос из UI
        _uiState.value = _uiState.value.copy(showCameraRequest = null)
        socketService?.clearCameraRequest()
    }

    /**
     * Завершить сессию
     */
    fun endSession(sessionId: String) {
        cameraService?.endSession(sessionId)
    }

    /**
     * Обработать WebRTC Offer
     */
    private fun handleWebRTCOffer(offer: WebRTCMessage) {
        val sessionId = offer.sessionId
        val offerSdp = offer.sdp ?: return

        Logger.d("Handling WebRTC offer for session: $sessionId")
        // В нашем случае мы не обрабатываем offer, так как создаем его сами
        // Но можно добавить логику для обработки offer от оператора
    }

    /**
     * Обработать WebRTC ICE Candidate
     */
    private fun handleWebRTCIceCandidate(candidate: WebRTCMessage) {
        val sessionId = candidate.sessionId
        val candidateSdp = candidate.candidate ?: return
        val sdpMid = candidate.sdpMid ?: return
        val sdpMLineIndex = candidate.sdpMLineIndex ?: return

        Logger.d("Handling ICE candidate for session: $sessionId")
        cameraService?.addIceCandidate(sessionId, candidateSdp, sdpMid, sdpMLineIndex)
    }

    /**
     * Обработать переключение камеры
     */
    private fun handleCameraSwitch(sessionId: String, newCameraType: String) {
        Logger.d("Handling camera switch for session $sessionId to $newCameraType")
        cameraService?.switchCamera(sessionId, newCameraType)
    }

    /**
     * Обработать отключение сессии
     */
    private fun handleSessionDisconnect(sessionId: String) {
        Logger.d("Handling session disconnect: $sessionId")
        cameraService?.endSession(sessionId)
    }

    /**
     * Очистить ошибку
     */
    fun clearError() {
        _uiState.value = _uiState.value.copy(error = null)
        socketService?.clearError()
        cameraService?.clearError()
    }

    /**
     * Проверить разрешения
     */
    fun checkPermissions(): Boolean {
        return permissionManager.hasAllRequiredPermissions()
    }

    /**
     * Получить отсутствующие разрешения
     */
    fun getMissingPermissions(): List<String> {
        return permissionManager.getMissingPermissions()
    }

    override fun onCleared() {
        super.onCleared()

        // Отвязка сервисов
        try {
            if (socketServiceBound) {
                context.unbindService(socketConnection)
                socketServiceBound = false
            }
            if (cameraServiceBound) {
                context.unbindService(cameraConnection)
                cameraServiceBound = false
            }
        } catch (e: Exception) {
            Logger.e("Error unbinding services", e)
        }

        Logger.d("MainViewModel cleared")
    }
}

/**
 * События UI для обработки в Activity/Compose
 */
sealed class UiEvent {
    object RequestPermissions : UiEvent()
    data class ShowError(val error: AppError) : UiEvent()
    data class ShowCameraRequestDialog(val request: CameraRequest) : UiEvent()
    data class ShowMessage(val message: String) : UiEvent()
}
