package com.radiola.data.repository

import com.radiola.domain.model.Station
import com.radiola.domain.model.StationTestResult
import com.radiola.domain.model.StationTestStatus
import com.radiola.domain.model.Track
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.Buffer
import java.io.IOException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StationTester @Inject constructor(
    private val okHttpClient: OkHttpClient
) {

    suspend fun test(station: Station, nowPlaying: Track?): StationTestResult {
        val testClient = okHttpClient.newBuilder()
            .connectTimeout(8, TimeUnit.SECONDS)
            .readTimeout(8, TimeUnit.SECONDS)
            .build()

        val request = Request.Builder()
            .url(station.streamUrl)
            .header("Icy-Metadata", "1")
            .build()

        return try {
            testClient.newCall(request).execute().use { response ->
                if (!response.isSuccessful) {
                    return StationTestResult(
                        stationId = station.id,
                        stationName = station.name,
                        streamUrl = station.streamUrl,
                        status = StationTestStatus.OFFLINE,
                        httpCode = response.code,
                        errorMessage = "HTTP ${response.code}"
                    )
                }

                val contentType = response.header("Content-Type")
                val hasAudio = contentType?.startsWith("audio") == true
                val metaint = response.header("icy-metaint")?.toIntOrNull()
                val hasIcy = metaint != null

                val icyTitle = if (hasIcy && metaint != null) {
                    readIcyTitle(response, metaint)
                } else null

                StationTestResult(
                    stationId = station.id,
                    stationName = station.name,
                    streamUrl = station.streamUrl,
                    status = when {
                        icyTitle != null || nowPlaying != null -> StationTestStatus.OK
                        hasAudio -> StationTestStatus.OK_NO_META
                        else -> StationTestStatus.OK_NO_META
                    },
                    httpCode = response.code,
                    contentType = contentType,
                    hasIcyMetadata = hasIcy,
                    icyTitle = icyTitle,
                    hasNowPlaying = nowPlaying != null,
                    nowPlayingTrack = nowPlaying?.let { "${it.artist} - ${it.song}" },
                    errorMessage = null
                )
            }
        } catch (e: IOException) {
            StationTestResult(
                stationId = station.id,
                stationName = station.name,
                streamUrl = station.streamUrl,
                status = StationTestStatus.OFFLINE,
                errorMessage = e.message ?: "Network error"
            )
        } catch (e: Exception) {
            StationTestResult(
                stationId = station.id,
                stationName = station.name,
                streamUrl = station.streamUrl,
                status = StationTestStatus.ERROR,
                errorMessage = e.message ?: "Unknown error"
            )
        }
    }

    private fun readIcyTitle(response: okhttp3.Response, metaint: Int): String? {
        return try {
            val source = response.body?.source() ?: return null
            val buffer = Buffer()

            var skipped = 0L
            while (skipped < metaint) {
                val toSkip = (metaint - skipped).coerceAtMost(8192)
                val actual = source.read(buffer, toSkip)
                if (actual == -1L) return null
                skipped += actual
            }
            buffer.clear()

            val metaLengthByte = source.readByte().toInt() and 0xFF
            if (metaLengthByte == 0) return null

            val metaBytes = source.readByteArray((metaLengthByte * 16).toLong())
            val metadata = String(metaBytes, Charsets.UTF_8).trim('\u0000')

            val regex = Regex("StreamTitle='([^']*)'")
            regex.find(metadata)?.groupValues?.get(1)?.trim()?.takeIf { it.isNotBlank() }
        } catch (e: Exception) {
            null
        }
    }
}
