package xyz.cottongin.radio247.ui.screens.settings

import android.app.Application
import android.content.ComponentName
import android.content.Intent
import android.net.Uri
import android.widget.Toast
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import xyz.cottongin.radio247.MainActivity
import xyz.cottongin.radio247.RadioApplication
import xyz.cottongin.radio247.data.importing.PlaylistExporter
import xyz.cottongin.radio247.data.model.MetadataSnapshot
import xyz.cottongin.radio247.data.model.Station
import xyz.cottongin.radio247.data.prefs.RadioPreferences
import xyz.cottongin.radio247.service.PlaybackState
import xyz.cottongin.radio247.service.StreamResolver
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONArray

@OptIn(ExperimentalCoroutinesApi::class)
class SettingsViewModel(application: Application) : AndroidViewModel(application) {
    private val app = application as RadioApplication

    val stayConnected = app.preferences.stayConnected.stateIn(
        viewModelScope, SharingStarted.Lazily, false
    )
    val bufferMs = app.preferences.bufferMs.stateIn(
        viewModelScope, SharingStarted.Lazily, 0
    )
    val qualityPreference = app.preferences.qualityPreference.stateIn(
        viewModelScope, SharingStarted.Lazily, RadioPreferences.DEFAULT_QUALITY_ORDER
    )
    val historyEnabled = app.preferences.historyEnabled.stateIn(
        viewModelScope, SharingStarted.Lazily, false
    )
    val historyFormat = app.preferences.historyFormat.stateIn(
        viewModelScope, SharingStarted.Lazily, "csv"
    )
    val historyDirUri = app.preferences.historyDirUri.stateIn(
        viewModelScope, SharingStarted.Lazily, ""
    )

    val recentSessions = app.database.listeningSessionDao()
        .getRecentSessions(50)
        .stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

    val trackHistory = MutableStateFlow("")

    val filteredTracks: StateFlow<List<MetadataSnapshot>> =
        trackHistory.flatMapLatest { query ->
            if (query.isBlank()) {
                app.database.metadataSnapshotDao().getRecent(100)
            } else {
                app.database.metadataSnapshotDao().search(query)
            }
        }.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

    val stations = app.database.stationDao()
        .getAllStations()
        .stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

    private val _isRestarting = MutableStateFlow(false)
    val isRestarting: StateFlow<Boolean> = _isRestarting

    fun setStayConnected(value: Boolean) {
        viewModelScope.launch { app.preferences.setStayConnected(value) }
    }

    fun setBufferMs(value: Int) {
        viewModelScope.launch { app.preferences.setBufferMs(value) }
    }

    fun setQualityPreference(orderedKeys: List<String>) {
        val json = JSONArray(orderedKeys).toString()
        viewModelScope.launch { app.preferences.setQualityPreference(json) }
    }

    fun setHistoryEnabled(value: Boolean) {
        viewModelScope.launch { app.preferences.setHistoryEnabled(value) }
    }

    fun setHistoryFormat(value: String) {
        viewModelScope.launch { app.preferences.setHistoryFormat(value) }
    }

    fun setHistoryDirUri(value: String) {
        viewModelScope.launch { app.preferences.setHistoryDirUri(value) }
    }

    fun exportPlaylist(
        playlistId: Long?,
        stations: List<Station>,
        format: String,
        uri: Uri
    ) {
        viewModelScope.launch(Dispatchers.IO) {
            val content = when (format) {
                "m3u" -> PlaylistExporter.toM3u(stations)
                "pls" -> PlaylistExporter.toPls(stations)
                else -> return@launch
            }
            app.contentResolver.openOutputStream(uri)?.use {
                it.write(content.toByteArray())
            }
        }
    }

    fun setTrackHistoryQuery(query: String) {
        trackHistory.value = query
    }

    fun resetCustomizations(alsoDeleteStations: Boolean) {
        viewModelScope.launch(Dispatchers.IO) {
            try {
                val db = app.database.openHelper.writableDatabase
                db.beginTransaction()
                try {
                    db.execSQL("UPDATE stations SET starred = 0, isHidden = 0, qualityOverride = NULL")
                    val cursor = db.query("SELECT id, sortOrder FROM stations ORDER BY id")
                    var idx = 0
                    while (cursor.moveToNext()) {
                        val id = cursor.getLong(0)
                        db.execSQL("UPDATE stations SET sortOrder = $idx WHERE id = $id")
                        idx++
                    }
                    cursor.close()

                    if (alsoDeleteStations) {
                        db.execSQL("DELETE FROM stations WHERE playlistId IN (SELECT id FROM playlists WHERE isBuiltIn = 0)")
                        db.execSQL("DELETE FROM stations WHERE playlistId IS NULL")
                        db.execSQL("DELETE FROM playlists WHERE isBuiltIn = 0")
                    }

                    db.setTransactionSuccessful()
                } finally {
                    db.endTransaction()
                }
                withContext(Dispatchers.Main) {
                    Toast.makeText(app, "Reset complete", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    Toast.makeText(app, "Reset failed: ${e.message}", Toast.LENGTH_LONG).show()
                }
            }
        }
    }

    fun restartApp() {
        _isRestarting.value = true
        viewModelScope.launch {
            app.controller.stop()

            var waited = 0L
            while (waited < 3000L && app.controller.state.value !is PlaybackState.Idle) {
                delay(200)
                waited += 200
            }

            val intent = Intent.makeRestartActivityTask(
                ComponentName(app, MainActivity::class.java)
            )
            app.startActivity(intent)
            Runtime.getRuntime().exit(0)
        }
    }

    fun parseQualityOrder(json: String): List<String> {
        return try {
            val arr = JSONArray(json)
            (0 until arr.length()).map { arr.getString(it) }
        } catch (_: Exception) {
            StreamResolver.DEFAULT_ORDER
        }
    }
}
