package de.hackernet.wireguardtv.ui

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.leanback.app.BrowseSupportFragment
import androidx.leanback.widget.*
import androidx.lifecycle.lifecycleScope
import de.hackernet.wireguardtv.R
import de.hackernet.wireguardtv.data.TunnelRepository
import de.hackernet.wireguardtv.model.TunnelConfig
import de.hackernet.wireguardtv.model.TunnelState
import de.hackernet.wireguardtv.model.TunnelStatus
import de.hackernet.wireguardtv.util.IpGeoService
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

/**
 * Haupt-Fragment mit Leanback BrowseSupportFragment
 * Zeigt Tunnel-Liste und Aktionen mit D-Pad Navigation
 */
class MainFragment : BrowseSupportFragment() {

    private lateinit var repository: TunnelRepository
    private lateinit var rowsAdapter: ArrayObjectAdapter
    private lateinit var tunnelRowAdapter: ArrayObjectAdapter

    private var currentStatus: TunnelStatus? = null
    private var webServerRunning = false
    private var webServerIp: String? = null
    private var webServerPort: Int = 8080

    // Geo-Info für IP-Standort Anzeige
    private var currentGeoInfo: IpGeoService.IpInfo? = null
    private var geoRefreshJob: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        repository = TunnelRepository.getInstance(requireContext())
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupUIElements()
        setupEventListeners()
        loadData()
        observeTunnels()
        startGeoRefresh()
    }

    override fun onResume() {
        super.onResume()
        // WebServer-Status aktualisieren wenn Fragment wieder sichtbar wird
        refreshWebServerStatus()
        // Geo-Refresh fortsetzen
        if (geoRefreshJob?.isActive != true) {
            startGeoRefresh()
        }
    }

    override fun onPause() {
        super.onPause()
        // Geo-Refresh pausieren wenn Fragment nicht sichtbar
        geoRefreshJob?.cancel()
    }

    /**
     * Startet periodische Aktualisierung der Geo-Information
     */
    private fun startGeoRefresh() {
        geoRefreshJob?.cancel()
        geoRefreshJob = lifecycleScope.launch {
            while (isActive) {
                try {
                    val geoInfo = IpGeoService.getPublicIpInfo()
                    if (geoInfo != currentGeoInfo) {
                        currentGeoInfo = geoInfo
                        updateGeoInfoRow()
                    }
                } catch (e: Exception) {
                    // Fehler ignorieren, nächster Versuch in 30s
                }
                delay(30_000) // Alle 30 Sekunden aktualisieren
            }
        }
    }

    /**
     * Aktualisiert nur die Geo-Info Row ohne kompletten UI-Rebuild
     */
    private fun updateGeoInfoRow() {
        // Geo-Info Row finden (Index 2) und aktualisieren
        if (rowsAdapter.size() >= 3) {
            val geoRow = rowsAdapter.get(2) as? ListRow
            val geoAdapter = geoRow?.adapter as? ArrayObjectAdapter
            if (geoAdapter != null && geoAdapter.size() > 0) {
                geoAdapter.replace(0, GeoInfoCardItem(currentGeoInfo))
            }
        }
    }

    /**
     * WebServer-Status von MainActivity abfragen und UI aktualisieren
     */
    private fun refreshWebServerStatus() {
        val mainActivity = activity as? MainActivity ?: return
        val isRunning = mainActivity.isWebServerRunning()
        if (isRunning) {
            val url = mainActivity.getWebServerUrl()
            // IP und Port aus URL extrahieren
            val regex = """http://([^:]+):(\d+)""".toRegex()
            val match = regex.find(url ?: "")
            val ip = match?.groupValues?.getOrNull(1)
            val port = match?.groupValues?.getOrNull(2)?.toIntOrNull() ?: 8080
            if (webServerRunning != isRunning || webServerIp != ip || webServerPort != port) {
                updateWebServerStatus(isRunning, ip, port)
            }
        } else if (webServerRunning) {
            // Server wurde gestoppt
            updateWebServerStatus(false, null, 8080)
        }
    }

    private fun setupUIElements() {
        // Header
        title = "WireGuard VPN"
        headersState = HEADERS_ENABLED
        isHeadersTransitionOnBackEnabled = true

        // Branding Colors
        brandColor = ContextCompat.getColor(requireContext(), R.color.brand_primary)
        searchAffordanceColor = ContextCompat.getColor(requireContext(), R.color.brand_accent)

        // Presenter Selector für verschiedene Card-Typen
        val presenterSelector = ClassPresenterSelector().apply {
            addClassPresenter(TunnelCardItem::class.java, TunnelCardPresenter())
            addClassPresenter(ActionCardItem::class.java, ActionCardPresenter())
            addClassPresenter(GeoInfoCardItem::class.java, GeoInfoCardPresenter())
        }

        rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
        adapter = rowsAdapter
    }

    private fun setupEventListeners() {
        // Item Klick Handler
        onItemViewClickedListener = OnItemViewClickedListener { _, item, _, _ ->
            when (item) {
                is TunnelCardItem -> handleTunnelClick(item)
                is ActionCardItem -> handleActionClick(item)
            }
        }

        // Item Selection für visuelle Feedback
        onItemViewSelectedListener = OnItemViewSelectedListener { _, item, _, _ ->
            // Optionales visuelles Feedback bei Fokus
        }
    }

    private fun loadData() {
        lifecycleScope.launch {
            val tunnels = repository.getTunnels()
            updateRows(tunnels)
        }
    }

    private fun observeTunnels() {
        lifecycleScope.launch {
            repository.tunnelsFlow.collectLatest { tunnels ->
                updateRows(tunnels)
            }
        }
    }

    private fun updateRows(tunnels: List<TunnelConfig>) {
        rowsAdapter.clear()

        // Row 1: Tunnel Liste
        tunnelRowAdapter = ArrayObjectAdapter(TunnelCardPresenter())
        tunnels.forEach { tunnel ->
            val isActive = currentStatus?.tunnelId == tunnel.id &&
                    currentStatus?.state == TunnelState.CONNECTED
            tunnelRowAdapter.add(TunnelCardItem(
                tunnel = tunnel,
                isConnected = isActive,
                status = if (isActive) currentStatus else null
            ))
        }

        if (tunnels.isEmpty()) {
            tunnelRowAdapter.add(TunnelCardItem.Empty)
        }

        val tunnelHeader = HeaderItem(0, "VPN Tunnel")
        rowsAdapter.add(ListRow(tunnelHeader, tunnelRowAdapter))

        // Row 2: Aktionen
        val actionsAdapter = ArrayObjectAdapter(ActionCardPresenter())
        actionsAdapter.add(ActionCardItem.AddTunnel)
        actionsAdapter.add(ActionCardItem.ImportFile)

        // Webserver Status anzeigen
        if (webServerRunning && webServerIp != null) {
            actionsAdapter.add(ActionCardItem.WebServerRunning(webServerIp!!, webServerPort))
        } else {
            actionsAdapter.add(ActionCardItem.WebServerStart)
        }

        actionsAdapter.add(ActionCardItem.Settings)

        val actionsHeader = HeaderItem(1, "Aktionen")
        rowsAdapter.add(ListRow(actionsHeader, actionsAdapter))

        // Row 3: Geo-Info (immer anzeigen)
        val geoAdapter = ArrayObjectAdapter(GeoInfoCardPresenter())
        geoAdapter.add(GeoInfoCardItem(currentGeoInfo))
        val geoHeader = HeaderItem(2, "Standort")
        rowsAdapter.add(ListRow(geoHeader, geoAdapter))

        // Row 4: VPN Status (nur wenn verbunden)
        if (currentStatus?.state == TunnelState.CONNECTED) {
            val statusAdapter = ArrayObjectAdapter(StatusCardPresenter())
            statusAdapter.add(StatusCardItem(currentStatus!!))

            val statusHeader = HeaderItem(3, "VPN Status")
            rowsAdapter.add(ListRow(statusHeader, statusAdapter))
        }
    }

    private fun handleTunnelClick(item: TunnelCardItem) {
        if (item == TunnelCardItem.Empty) {
            // Leere Karte -> Tunnel hinzufügen
            startActivity(Intent(requireContext(), TunnelEditorActivity::class.java))
            return
        }

        // Zeige Aktions-Dialog für den Tunnel
        val fragment = TunnelActionDialogFragment.newInstance(
            tunnelId = item.tunnel.id,
            tunnelName = item.tunnel.name,
            isConnected = item.isConnected
        )
        TunnelActionDialogFragment.show(parentFragmentManager, fragment)
    }

    private fun handleActionClick(item: ActionCardItem) {
        val activity = requireActivity() as MainActivity

        when (item) {
            ActionCardItem.AddTunnel -> {
                startActivity(Intent(requireContext(), TunnelEditorActivity::class.java))
            }
            ActionCardItem.ImportFile -> {
                // Datei-Import Activity starten
                startActivity(Intent(requireContext(), FileImportActivity::class.java))
            }
            ActionCardItem.WebServerStart -> {
                // Zeige WebServer Dialog
                val fragment = WebServerActionDialogFragment.newInstance(
                    isRunning = false,
                    serverIp = null
                )
                WebServerActionDialogFragment.show(parentFragmentManager, fragment)
            }
            is ActionCardItem.WebServerRunning -> {
                // Zeige WebServer Dialog mit aktuellem Status
                val fragment = WebServerActionDialogFragment.newInstance(
                    isRunning = true,
                    serverIp = item.ip
                )
                WebServerActionDialogFragment.show(parentFragmentManager, fragment)
            }
            ActionCardItem.Settings -> {
                startActivity(Intent(requireContext(), SettingsActivity::class.java))
            }
            else -> {}
        }
    }

    /**
     * Tunnel Status Update (vom Service)
     */
    fun updateTunnelStatus(status: TunnelStatus?) {
        val previousState = currentStatus?.state
        val newState = status?.state
        currentStatus = status

        // Nur bei State-Änderung komplett neu laden (nicht bei jedem Stats-Update)
        if (previousState != newState) {
            lifecycleScope.launch {
                val tunnels = repository.getTunnels()
                updateRows(tunnels)
            }
        } else if (newState == TunnelState.CONNECTED) {
            // Bei Stats-Updates nur die Status-Karte aktualisieren (ohne kompletten Rebuild)
            updateStatusCard()
        }
    }

    /**
     * Aktualisiert nur die Status-Karte ohne kompletten UI-Rebuild
     */
    private fun updateStatusCard() {
        // Finde die Status-Row (Index 3, nach Geo-Info) und aktualisiere sie
        if (rowsAdapter.size() >= 4 && currentStatus != null) {
            val statusRow = rowsAdapter.get(3) as? ListRow
            val statusAdapter = statusRow?.adapter as? ArrayObjectAdapter
            if (statusAdapter != null && statusAdapter.size() > 0) {
                statusAdapter.replace(0, StatusCardItem(currentStatus!!))
            }
        }
    }

    /**
     * Webserver Status Update
     */
    fun updateWebServerStatus(running: Boolean, ip: String?, port: Int = 8080) {
        webServerRunning = running
        webServerIp = ip
        webServerPort = port
        lifecycleScope.launch {
            val tunnels = repository.getTunnels()
            updateRows(tunnels)
        }
    }

    /**
     * Liste aktualisieren (nach Config-Import)
     */
    fun refreshTunnelList() {
        loadData()
    }
}

/**
 * Datenklassen für die Leanback Cards
 */
data class TunnelCardItem(
    val tunnel: TunnelConfig,
    val isConnected: Boolean = false,
    val status: TunnelStatus? = null
) {
    companion object {
        val Empty = TunnelCardItem(
            tunnel = TunnelConfig(
                id = "empty",
                name = "Kein Tunnel",
                interface_ = de.hackernet.wireguardtv.model.InterfaceConfig(
                    privateKey = "",
                    addresses = emptyList()
                ),
                peers = emptyList()
            ),
            isConnected = false
        )
    }
}

sealed class ActionCardItem(val title: String, val description: String, val icon: Int) {
    object AddTunnel : ActionCardItem("Tunnel hinzufügen", "Manuell konfigurieren", R.drawable.ic_add)
    object ImportFile : ActionCardItem("Datei importieren", "Config von Speicher laden", R.drawable.ic_folder)
    object WebServerStart : ActionCardItem("Web-Upload", "Server starten/konfigurieren", R.drawable.ic_web)
    data class WebServerRunning(val ip: String, val port: Int = 8080) : ActionCardItem("Web-Upload aktiv", "http://$ip:$port", R.drawable.ic_web)
    object Settings : ActionCardItem("Einstellungen", "", R.drawable.ic_settings)
}

data class StatusCardItem(val status: TunnelStatus)

/**
 * Presenter für Tunnel Cards
 */
class TunnelCardPresenter : Presenter() {
    override fun onCreateViewHolder(parent: android.view.ViewGroup): ViewHolder {
        val cardView = androidx.leanback.widget.ImageCardView(parent.context).apply {
            isFocusable = true
            isFocusableInTouchMode = true
            setMainImageDimensions(200, 200)
        }
        return ViewHolder(cardView)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        val tunnelItem = item as TunnelCardItem

        if (tunnelItem == TunnelCardItem.Empty) {
            cardView.titleText = "Kein Tunnel konfiguriert"
            cardView.contentText = "Tippen zum Hinzufügen"
            cardView.setMainImageScaleType(android.widget.ImageView.ScaleType.CENTER_INSIDE)
            cardView.mainImageView.setImageResource(R.drawable.ic_add)
        } else {
            cardView.titleText = tunnelItem.tunnel.name
            cardView.contentText = if (tunnelItem.isConnected) {
                "Verbunden"
            } else {
                tunnelItem.tunnel.peers.firstOrNull()?.endpoint ?: "Nicht verbunden"
            }

            val iconRes = if (tunnelItem.isConnected) {
                R.drawable.ic_vpn_connected
            } else {
                R.drawable.ic_vpn_disconnected
            }
            cardView.mainImageView.setImageResource(iconRes)

            // Farbiges Badge für Status
            cardView.badgeImage = if (tunnelItem.isConnected) {
                ContextCompat.getDrawable(cardView.context, R.drawable.badge_connected)
            } else {
                null
            }
        }
    }

    override fun onUnbindViewHolder(viewHolder: ViewHolder) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        cardView.mainImage = null
        cardView.badgeImage = null
    }
}

/**
 * Presenter für Action Cards
 */
class ActionCardPresenter : Presenter() {
    override fun onCreateViewHolder(parent: android.view.ViewGroup): ViewHolder {
        val cardView = androidx.leanback.widget.ImageCardView(parent.context).apply {
            isFocusable = true
            isFocusableInTouchMode = true
            setMainImageDimensions(150, 150)
        }
        return ViewHolder(cardView)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        val actionItem = item as ActionCardItem

        cardView.titleText = actionItem.title
        cardView.contentText = actionItem.description
        cardView.mainImageView.setImageResource(actionItem.icon)
        cardView.setMainImageScaleType(android.widget.ImageView.ScaleType.CENTER_INSIDE)
    }

    override fun onUnbindViewHolder(viewHolder: ViewHolder) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        cardView.mainImage = null
    }
}

/**
 * Presenter für Status Cards
 */
class StatusCardPresenter : Presenter() {
    override fun onCreateViewHolder(parent: android.view.ViewGroup): ViewHolder {
        val cardView = androidx.leanback.widget.ImageCardView(parent.context).apply {
            isFocusable = true
            isFocusableInTouchMode = true
            setMainImageDimensions(300, 150)
        }
        return ViewHolder(cardView)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        val statusItem = item as StatusCardItem

        // Titel mit Flagge und Land wenn verfügbar
        val titleText = if (statusItem.status.publicIp != null && statusItem.status.countryFlag != null) {
            "${statusItem.status.countryFlag} ${statusItem.status.publicIp}"
        } else {
            "Verbindungsstatistik"
        }
        cardView.titleText = titleText

        cardView.contentText = buildString {
            // Land anzeigen wenn verfügbar
            if (statusItem.status.countryName != null) {
                append(statusItem.status.countryName)
                append(" | ")
            }
            append("↓ ${formatBytes(statusItem.status.rxBytes)}")
            append(" | ")
            append("↑ ${formatBytes(statusItem.status.txBytes)}")
        }
        cardView.mainImageView.setImageResource(R.drawable.ic_stats)
    }

    override fun onUnbindViewHolder(viewHolder: ViewHolder) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        cardView.mainImage = null
    }

    private fun formatBytes(bytes: Long): String {
        return when {
            bytes < 1024 -> "$bytes B"
            bytes < 1024 * 1024 -> "${bytes / 1024} KB"
            bytes < 1024 * 1024 * 1024 -> "${bytes / (1024 * 1024)} MB"
            else -> "${bytes / (1024 * 1024 * 1024)} GB"
        }
    }
}

/**
 * Datenklasse für Geo-Info Card
 */
data class GeoInfoCardItem(val geoInfo: IpGeoService.IpInfo?)

/**
 * Presenter für Geo-Info Cards (zeigt öffentliche IP und Standort)
 * Dreifache Größe für bessere Sichtbarkeit
 */
class GeoInfoCardPresenter : Presenter() {
    override fun onCreateViewHolder(parent: android.view.ViewGroup): ViewHolder {
        val cardView = androidx.leanback.widget.ImageCardView(parent.context).apply {
            isFocusable = true
            isFocusableInTouchMode = true
            // Dreifache Größe: 600x450 statt 200x150
            setMainImageDimensions(600, 450)
        }
        return ViewHolder(cardView)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        val geoItem = item as GeoInfoCardItem

        if (geoItem.geoInfo != null) {
            val info = geoItem.geoInfo
            // Titel: Flagge und IP
            cardView.titleText = "${info.flag} ${info.ip}"
            // Content: Land und optional Stadt
            cardView.contentText = if (info.city != null) {
                "${info.countryName}, ${info.city}"
            } else {
                info.countryName
            }
            cardView.mainImageView.setImageResource(R.drawable.ic_location)
        } else {
            cardView.titleText = "Standort wird ermittelt..."
            cardView.contentText = "Bitte warten"
            cardView.mainImageView.setImageResource(R.drawable.ic_location)
        }
        cardView.setMainImageScaleType(android.widget.ImageView.ScaleType.CENTER_INSIDE)
    }

    override fun onUnbindViewHolder(viewHolder: ViewHolder) {
        val cardView = viewHolder.view as androidx.leanback.widget.ImageCardView
        cardView.mainImage = null
    }
}
