package com.radiola.service

import android.content.Context
import android.media.audiofx.BassBoost
import android.media.audiofx.Equalizer
import android.media.audiofx.LoudnessEnhancer
import android.media.audiofx.Virtualizer
import android.util.Log
import com.radiola.domain.repository.SettingsRepository
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

/** Одна полоса эквалайзера: центральная частота и текущий/предельный уровень в мБ. */
data class EqBand(
    val index: Int,
    val centerHz: Int,
    val minMb: Int,
    val maxMb: Int,
    val levelMb: Int
)

/** Снимок состояния эквалайзера и улучшайзеров для UI. */
data class EqState(
    val available: Boolean = false,
    val enabled: Boolean = false,
    val bands: List<EqBand> = emptyList(),
    val presets: List<String> = emptyList(),
    val currentPreset: Int = -1, // -1 = свой
    val hasBass: Boolean = false,
    val hasVirtualizer: Boolean = false,
    val hasLoudness: Boolean = false,
    val bass: Int = 0,        // 0..100 %
    val virtualizer: Int = 0, // 0..100 %
    val loudness: Int = 0     // 0..100 % → 0..+12 дБ
)

/**
 * Управляет системными аудиоэффектами (android.media.audiofx), привязанными к
 * аудиосессии плеера: графический эквалайзер + Bass Boost + Virtualizer (объём) +
 * LoudnessEnhancer (громкость тихих). Применяет в реальном времени, переживает смену
 * станции (сессия фиксированная), сохраняет настройки в DataStore. Эффекты — best-effort:
 * на устройствах без поддержки соответствующий блок просто недоступен (null).
 */
@Singleton
class AudioEffectsController @Inject constructor(
    @ApplicationContext private val context: Context,
    private val settings: SettingsRepository
) {
    private val tag = "AudioEffects"
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    private var equalizer: Equalizer? = null
    private var bassBoost: BassBoost? = null
    private var virtualizer: Virtualizer? = null
    private var loudness: LoudnessEnhancer? = null
    private var masterEnabled = false

    private val _state = MutableStateFlow(EqState())
    val state: StateFlow<EqState> = _state.asStateFlow()

    /** Привязывает эффекты к аудиосессии и применяет сохранённые настройки. */
    fun attach(sessionId: Int) {
        release()
        equalizer = try {
            Equalizer(0, sessionId)
        } catch (e: Exception) {
            Log.w(tag, "Equalizer недоступен: ${e.message}"); null
        }
        bassBoost = try {
            BassBoost(0, sessionId).let { if (it.strengthSupported) it else { it.release(); null } }
        } catch (e: Exception) {
            null
        }
        virtualizer = try {
            Virtualizer(0, sessionId).let { if (it.strengthSupported) it else { it.release(); null } }
        } catch (e: Exception) {
            null
        }
        loudness = try {
            LoudnessEnhancer(sessionId)
        } catch (e: Exception) {
            null
        }
        scope.launch { loadAndApply() }
    }

    private suspend fun loadAndApply() {
        val enabled = settings.getEqEnabled().first()
        val preset = settings.getEqPreset().first()
        val bandsCsv = settings.getEqBands().first()
        val bass = settings.getEqBass().first()
        val virt = settings.getEqVirtualizer().first()
        val loud = settings.getEqLoudness().first()

        masterEnabled = enabled
        val eq = equalizer
        if (eq != null) {
            runCatching { eq.enabled = enabled }
            val saved = bandsCsv.split(",").mapNotNull { it.trim().toShortOrNull() }
            if (preset in 0 until eq.numberOfPresets) {
                runCatching { eq.usePreset(preset.toShort()) }
            } else if (saved.size == eq.numberOfBands.toInt()) {
                saved.forEachIndexed { i, lvl -> runCatching { eq.setBandLevel(i.toShort(), lvl) } }
            }
        }
        applyBassInternal(bass)
        applyVirtualizerInternal(virt)
        applyLoudnessInternal(loud)
        emitState(enabled, preset, bass, virt, loud)
    }

    // ── Публичные действия (UI) ──

    fun setEnabled(on: Boolean) {
        masterEnabled = on
        runCatching { equalizer?.enabled = on }
        val s = _state.value
        applyBassInternal(s.bass)
        applyVirtualizerInternal(s.virtualizer)
        applyLoudnessInternal(s.loudness)
        persist { settings.setEqEnabled(on) }
        _state.value = s.copy(enabled = on)
    }

    fun selectPreset(index: Int) {
        val eq = equalizer ?: return
        if (index !in 0 until eq.numberOfPresets) return
        runCatching { eq.usePreset(index.toShort()) }
        persist { settings.setEqPreset(index); settings.setEqBands(currentBandsCsv()) }
        emitState(_state.value.enabled, index, _state.value.bass, _state.value.virtualizer, _state.value.loudness)
    }

    // setBand/setBass/... применяют к железу + правят in-memory состояние БЕЗ записи в
    // DataStore (вызываются на каждое движение слайдера). Запись — один раз в commit()
    // на onValueChangeFinished, чтобы не спамить хранилище десятками правок за драг.

    fun setBand(index: Int, levelMb: Int) {
        val eq = equalizer ?: return
        runCatching { eq.setBandLevel(index.toShort(), levelMb.toShort()) }
        val s = _state.value
        _state.value = s.copy(
            currentPreset = -1, // ручная правка → «свой»
            bands = s.bands.map { if (it.index == index) it.copy(levelMb = levelMb) else it }
        )
    }

    fun setBass(value: Int) {
        applyBassInternal(value)
        _state.value = _state.value.copy(bass = value)
    }

    fun setVirtualizer(value: Int) {
        applyVirtualizerInternal(value)
        _state.value = _state.value.copy(virtualizer = value)
    }

    fun setLoudness(value: Int) {
        applyLoudnessInternal(value)
        _state.value = _state.value.copy(loudness = value)
    }

    /** Сохраняет текущее состояние полос/улучшайзеров (вызывать при отпускании слайдера). */
    fun commit() {
        val s = _state.value
        persist {
            settings.setEqPreset(s.currentPreset)
            settings.setEqBands(currentBandsCsv())
            settings.setEqBass(s.bass)
            settings.setEqVirtualizer(s.virtualizer)
            settings.setEqLoudness(s.loudness)
        }
    }

    // ── Внутреннее применение к железу ──

    private fun applyBassInternal(value: Int) {
        val bb = bassBoost ?: return
        runCatching {
            bb.enabled = masterEnabled && value > 0
            if (masterEnabled && value > 0) bb.setStrength((value.coerceIn(0, 100) * 10).toShort())
        }
    }

    private fun applyVirtualizerInternal(value: Int) {
        val vz = virtualizer ?: return
        runCatching {
            vz.enabled = masterEnabled && value > 0
            if (masterEnabled && value > 0) vz.setStrength((value.coerceIn(0, 100) * 10).toShort())
        }
    }

    private fun applyLoudnessInternal(value: Int) {
        val le = loudness ?: return
        runCatching {
            le.enabled = masterEnabled && value > 0
            // 0..100 % → 0..1200 мБ (= 0..+12 дБ)
            if (masterEnabled && value > 0) le.setTargetGain(value.coerceIn(0, 100) * 12)
        }
    }

    private fun currentBandsCsv(): String {
        val eq = equalizer ?: return ""
        return (0 until eq.numberOfBands).joinToString(",") { eq.getBandLevel(it.toShort()).toString() }
    }

    private fun emitState(enabled: Boolean, preset: Int, bass: Int, virt: Int, loud: Int) {
        val eq = equalizer
        val bands = if (eq != null) {
            val range = eq.bandLevelRange // [min, max] в мБ
            (0 until eq.numberOfBands).map { i ->
                val b = i.toShort()
                EqBand(
                    index = i,
                    centerHz = eq.getCenterFreq(b) / 1000, // мГц → Гц
                    minMb = range[0].toInt(),
                    maxMb = range[1].toInt(),
                    levelMb = eq.getBandLevel(b).toInt()
                )
            }
        } else emptyList()
        val presets = if (eq != null) {
            (0 until eq.numberOfPresets).map { eq.getPresetName(it.toShort()) }
        } else emptyList()
        _state.value = EqState(
            available = eq != null,
            enabled = enabled,
            bands = bands,
            presets = presets,
            currentPreset = preset,
            hasBass = bassBoost != null,
            hasVirtualizer = virtualizer != null,
            hasLoudness = loudness != null,
            bass = bass,
            virtualizer = virt,
            loudness = loud
        )
    }

    private fun persist(block: suspend () -> Unit) {
        scope.launch { runCatching { block() } }
    }

    fun release() {
        runCatching { equalizer?.release() }
        runCatching { bassBoost?.release() }
        runCatching { virtualizer?.release() }
        runCatching { loudness?.release() }
        equalizer = null; bassBoost = null; virtualizer = null; loudness = null
    }
}
