package xyz.cottongin.radio247.ui.screens.stationlist

import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.Upload
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilterChip
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil3.compose.AsyncImage
import xyz.cottongin.radio247.data.model.Playlist
import xyz.cottongin.radio247.data.model.Station
import xyz.cottongin.radio247.data.model.StationStream
import xyz.cottongin.radio247.service.PlaybackState
import xyz.cottongin.radio247.service.StreamResolver
import org.json.JSONArray
import xyz.cottongin.radio247.ui.components.MiniPlayer

private class TabDragState {
    var isDragging by mutableStateOf(false)
    var draggedIndex by mutableIntStateOf(-1)
    var dragOffset by mutableFloatStateOf(0f)
    var currentTabs by mutableStateOf<List<TabInfo>>(emptyList())
}

@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun StationListScreen(
    onNavigateToNowPlaying: () -> Unit,
    onNavigateToSettings: () -> Unit,
    modifier: Modifier = Modifier,
    viewModel: StationListViewModel = viewModel(
        factory = StationListViewModelFactory(
            LocalContext.current.applicationContext as xyz.cottongin.radio247.RadioApplication
        )
    )
) {
    val viewState by viewModel.viewState.collectAsState()
    val playbackState by viewModel.playbackState.collectAsState()
    val pendingImport by viewModel.pendingImport.collectAsState()

    var showAddStation by remember { mutableStateOf(false) }
    var showAddPlaylist by remember { mutableStateOf(false) }
    var stationToEdit by remember { mutableStateOf<Station?>(null) }
    var stationForQuality by remember { mutableStateOf<Station?>(null) }
    var qualityStreams by remember { mutableStateOf<List<StationStream>>(emptyList()) }
    var qualityCurrentOrder by remember { mutableStateOf<List<String>>(emptyList()) }
    var tabToRename by remember { mutableStateOf<TabInfo?>(null) }

    val importLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.OpenDocument(),
        onResult = { uri: Uri? ->
            uri?.let { viewModel.importFile(it) }
        }
    )

    val currentTab = viewState.tabs.getOrNull(viewState.selectedTabIndex)
    val isBuiltInTab = currentTab?.isBuiltIn == true

    Scaffold(
        modifier = modifier,
        topBar = {
            TopAppBar(
                title = { Text("24/7 Radio") },
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = MaterialTheme.colorScheme.surface,
                    titleContentColor = MaterialTheme.colorScheme.onSurface
                ),
                actions = {
                    if (!isBuiltInTab) {
                        IconButton(onClick = {
                            importLauncher.launch(
                                arrayOf("audio/*", "application/x-mpegurl", "*/*")
                            )
                        }) {
                            Icon(Icons.Default.Upload, contentDescription = "Import")
                        }
                        IconButton(onClick = { showAddStation = true }) {
                            Icon(Icons.Default.Add, contentDescription = "Add Station")
                        }
                    }
                    if (currentTab?.playlist != null && !isBuiltInTab) {
                        IconButton(onClick = { viewModel.deletePlaylist(currentTab.playlist) }) {
                            Icon(Icons.Default.Delete, contentDescription = "Delete Tab")
                        }
                    }
                    IconButton(onClick = onNavigateToSettings) {
                        Icon(Icons.Default.Settings, contentDescription = "Settings")
                    }
                }
            )
        },
        bottomBar = {
            when (playbackState) {
                is PlaybackState.Connecting,
                is PlaybackState.Playing,
                is PlaybackState.Paused,
                is PlaybackState.Reconnecting -> MiniPlayer(
                    state = playbackState,
                    onTap = onNavigateToNowPlaying,
                    onStop = { viewModel.controller.stop() }
                )
                PlaybackState.Idle -> {}
            }
        }
    ) { paddingValues ->
        val currentPlayingStationId = when (val state = playbackState) {
            is PlaybackState.Connecting -> state.station.id
            is PlaybackState.Playing -> state.station.id
            is PlaybackState.Paused -> state.station.id
            is PlaybackState.Reconnecting -> state.station.id
            PlaybackState.Idle -> null
        }

        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            if (viewState.tabs.size > 1) {
                DragReorderTabRow(
                    tabs = viewState.tabs,
                    selectedTabIndex = viewState.selectedTabIndex,
                    onSelectTab = { viewModel.selectTab(it) },
                    onReorderTabs = { viewModel.reorderTabs(it) },
                    onRenameRequested = { tabToRename = it },
                    onTogglePinned = { viewModel.togglePinned(it) }
                )
            }

            SortChipRow(
                sortMode = viewState.sortMode,
                isBuiltInTab = isBuiltInTab,
                isPolling = viewState.isPollingListeners,
                hiddenCount = viewState.hiddenCount,
                showHidden = viewState.showHidden,
                onSortChanged = { viewModel.setSortMode(it) },
                onRefreshListeners = { viewModel.refreshListenerCounts() },
                onToggleShowHidden = { viewModel.toggleShowHidden() }
            )

            val listState = rememberLazyListState()
            LaunchedEffect(viewState.sortMode, viewState.selectedTabIndex, viewState.showHidden) {
                listState.scrollToItem(0)
            }

            LazyColumn(
                state = listState,
                modifier = Modifier
                    .fillMaxSize()
                    .padding(horizontal = 16.dp)
            ) {
                if (viewState.stations.isEmpty()) {
                    item {
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(vertical = 48.dp),
                            contentAlignment = Alignment.Center
                        ) {
                            Text(
                                text = when {
                                    viewState.showHidden -> "No hidden stations"
                                    currentTab?.playlist == null -> "No stations yet"
                                    else -> "No stations in this playlist"
                                },
                                style = MaterialTheme.typography.bodyLarge,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                        }
                    }
                }

                items(
                    items = viewState.stations,
                    key = { it.id }
                ) { station ->
                    val hasStreams = station.id in viewState.stationIdsWithStreams
                    StationRow(
                        station = station,
                        isNowPlaying = station.id == currentPlayingStationId,
                        showListeners = isBuiltInTab,
                        isBuiltIn = isBuiltInTab,
                        isHiddenView = viewState.showHidden,
                        hasStreams = hasStreams,
                        onPlay = { viewModel.playStation(station) },
                        onToggleStar = { viewModel.toggleStar(station) },
                        onEdit = { stationToEdit = station },
                        onDelete = { viewModel.deleteStation(station) },
                        onToggleHidden = { viewModel.toggleHidden(station) },
                        onQuality = {
                            viewModel.getStreamsForStation(station.id) { streams ->
                                viewModel.getQualityOverrideForStation(station.id) { json ->
                                    qualityStreams = streams
                                    qualityCurrentOrder = if (json != null) {
                                        try {
                                            val arr = JSONArray(json)
                                            (0 until arr.length()).map { arr.getString(it) }
                                        } catch (_: Exception) {
                                            StreamResolver.DEFAULT_ORDER
                                        }
                                    } else {
                                        emptyList()
                                    }
                                    stationForQuality = station
                                }
                            }
                        }
                    )
                }

                if (currentTab?.playlist == null && viewState.stations.isNotEmpty()) {
                    item {
                        Spacer(modifier = Modifier.height(8.dp))
                    }
                }
            }
        }
    }

    if (showAddStation) {
        AddStationDialog(
            onDismiss = { showAddStation = false },
            onConfirm = { name, url ->
                viewModel.addStation(name, url)
                showAddStation = false
            }
        )
    }

    if (showAddPlaylist) {
        AddPlaylistDialog(
            onDismiss = { showAddPlaylist = false },
            onConfirm = { name ->
                viewModel.addPlaylist(name)
                showAddPlaylist = false
            }
        )
    }

    stationToEdit?.let { station ->
        EditStationDialog(
            station = station,
            onDismiss = { stationToEdit = null },
            onConfirm = { name, url ->
                viewModel.updateStation(station, name, url)
                stationToEdit = null
            }
        )
    }

    stationForQuality?.let { station ->
        val availableQualities = qualityStreams
            .map { "${it.bitrate}-${if (it.ssl) "ssl" else "nossl"}" }
            .distinct()
        QualityOverrideDialog(
            currentOrder = qualityCurrentOrder,
            availableQualities = availableQualities,
            onDismiss = {
                stationForQuality = null
                qualityStreams = emptyList()
                qualityCurrentOrder = emptyList()
            },
            onSave = { qualityJson ->
                viewModel.setQualityOverride(station.id, qualityJson)
                stationForQuality = null
                qualityStreams = emptyList()
                qualityCurrentOrder = emptyList()
            }
        )
    }

    pendingImport?.let { pending ->
        NamePlaylistDialog(
            suggestedName = pending.suggestedName,
            onDismiss = { viewModel.cancelImport() },
            onConfirm = { name -> viewModel.confirmImport(name) }
        )
    }

    tabToRename?.let { tab ->
        RenamePlaylistDialog(
            currentName = tab.label,
            onDismiss = { tabToRename = null },
            onConfirm = { newName ->
                tab.playlist?.let { viewModel.renamePlaylist(it, newName) }
                tabToRename = null
            }
        )
    }
}

@Composable
private fun DragReorderTabRow(
    tabs: List<TabInfo>,
    selectedTabIndex: Int,
    onSelectTab: (Int) -> Unit,
    onReorderTabs: (List<Playlist>) -> Unit,
    onRenameRequested: (TabInfo) -> Unit,
    onTogglePinned: (Playlist) -> Unit
) {
    val dragState = remember { TabDragState() }
    val scrollState = rememberScrollState()
    val density = LocalDensity.current
    val swapThresholdPx = with(density) { 48.dp.toPx() }

    LaunchedEffect(tabs) {
        if (!dragState.isDragging) {
            dragState.currentTabs = tabs
        }
    }

    val displayTabs = if (dragState.isDragging) dragState.currentTabs else tabs
    val myStationsIndex = tabs.indexOfFirst { it.playlist == null }
    val pinnedEnd = if (myStationsIndex >= 0) myStationsIndex else tabs.size
    val unpinnedStart = if (myStationsIndex >= 0) myStationsIndex + 1 else tabs.size

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .horizontalScroll(scrollState)
    ) {
        Row(
            modifier = Modifier.padding(horizontal = 16.dp),
            horizontalArrangement = Arrangement.spacedBy(0.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            displayTabs.forEachIndexed { index, tab ->
                key(tab.playlist?.id ?: -1L) {
                val isDraggable = tab.playlist != null
                var showTabMenu by remember(tab) { mutableStateOf(false) }
                var totalDragDistance by remember { mutableFloatStateOf(0f) }
                val dragThreshold = swapThresholdPx / 3

                val tabModifier = Modifier
                    .then(
                        if (dragState.isDragging && dragState.draggedIndex == index) {
                            Modifier.graphicsLayer { translationX = dragState.dragOffset }
                        } else {
                            Modifier
                        }
                    )
                    .then(
                        if (isDraggable) {
                            Modifier.pointerInput(tabs) {
                                detectDragGesturesAfterLongPress(
                                    onDragStart = {
                                        totalDragDistance = 0f
                                        dragState.isDragging = true
                                        dragState.draggedIndex = index
                                        dragState.dragOffset = 0f
                                        dragState.currentTabs = ArrayList(tabs)
                                    },
                                    onDrag = { change, dragAmount ->
                                        change.consume()
                                        totalDragDistance += kotlin.math.abs(dragAmount.x) + kotlin.math.abs(dragAmount.y)
                                        val currentIndex = dragState.draggedIndex
                                        val newOffset = dragState.dragOffset + dragAmount.x
                                        val groupStart = if (currentIndex < pinnedEnd) 0 else unpinnedStart
                                        val groupEnd = if (currentIndex < pinnedEnd) pinnedEnd else tabs.size

                                        if (newOffset > swapThresholdPx && currentIndex + 1 < groupEnd) {
                                            val mutable = dragState.currentTabs.toMutableList()
                                            val tmp = mutable[currentIndex]
                                            mutable[currentIndex] = mutable[currentIndex + 1]
                                            mutable[currentIndex + 1] = tmp
                                            dragState.currentTabs = mutable
                                            dragState.draggedIndex = currentIndex + 1
                                            dragState.dragOffset = 0f
                                        } else if (newOffset < -swapThresholdPx && currentIndex - 1 >= groupStart) {
                                            val mutable = dragState.currentTabs.toMutableList()
                                            val tmp = mutable[currentIndex]
                                            mutable[currentIndex] = mutable[currentIndex - 1]
                                            mutable[currentIndex - 1] = tmp
                                            dragState.currentTabs = mutable
                                            dragState.draggedIndex = currentIndex - 1
                                            dragState.dragOffset = 0f
                                        } else {
                                            dragState.dragOffset = newOffset
                                        }
                                    },
                                    onDragEnd = {
                                        if (totalDragDistance < dragThreshold) {
                                            showTabMenu = true
                                        } else {
                                            val reordered = dragState.currentTabs
                                            val playlists = if (dragState.draggedIndex < pinnedEnd) {
                                                reordered.subList(0, pinnedEnd).mapNotNull { it.playlist }
                                            } else {
                                                reordered.subList(unpinnedStart, reordered.size).mapNotNull { it.playlist }
                                            }
                                            if (playlists.isNotEmpty()) {
                                                onReorderTabs(playlists)
                                            }
                                        }
                                        dragState.isDragging = false
                                        dragState.draggedIndex = -1
                                        dragState.dragOffset = 0f
                                    },
                                    onDragCancel = {
                                        if (totalDragDistance < dragThreshold) {
                                            showTabMenu = true
                                        }
                                        dragState.isDragging = false
                                        dragState.draggedIndex = -1
                                        dragState.dragOffset = 0f
                                    }
                                )
                            }
                        } else {
                            Modifier
                        }
                    )

                Box {
                    Tab(
                        selected = selectedTabIndex == index,
                        onClick = { onSelectTab(index) },
                        text = {
                            Text(
                                text = tab.label,
                                maxLines = 1,
                                overflow = TextOverflow.Ellipsis
                            )
                        },
                        modifier = tabModifier
                    )
                    DropdownMenu(
                        expanded = showTabMenu,
                        onDismissRequest = { showTabMenu = false }
                    ) {
                        if (tab.playlist != null && !tab.isBuiltIn) {
                            DropdownMenuItem(
                                text = { Text("Rename") },
                                onClick = {
                                    showTabMenu = false
                                    onRenameRequested(tab)
                                }
                            )
                        }
                        if (tab.playlist != null) {
                            DropdownMenuItem(
                                text = { Text(if (tab.playlist.pinned) "Unpin" else "Pin") },
                                onClick = {
                                    showTabMenu = false
                                    onTogglePinned(tab.playlist)
                                }
                            )
                        }
                    }
                }
                }
            }
        }
    }
}

@Composable
private fun SortChipRow(
    sortMode: SortMode,
    isBuiltInTab: Boolean,
    isPolling: Boolean,
    hiddenCount: Int,
    showHidden: Boolean,
    onSortChanged: (SortMode) -> Unit,
    onRefreshListeners: () -> Unit,
    onToggleShowHidden: () -> Unit,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 4.dp),
        horizontalArrangement = Arrangement.spacedBy(8.dp),
        verticalAlignment = Alignment.CenterVertically
    ) {
        FilterChip(
            selected = sortMode == SortMode.DEFAULT,
            onClick = { onSortChanged(SortMode.DEFAULT) },
            label = { Text("Default") }
        )
        FilterChip(
            selected = sortMode == SortMode.NAME_ASC,
            onClick = { onSortChanged(SortMode.NAME_ASC) },
            label = { Text("A-Z") }
        )
        FilterChip(
            selected = sortMode == SortMode.NAME_DESC,
            onClick = { onSortChanged(SortMode.NAME_DESC) },
            label = { Text("Z-A") }
        )
        if (isBuiltInTab) {
            IconButton(
                onClick = onRefreshListeners,
                enabled = !isPolling,
                modifier = Modifier.size(32.dp)
            ) {
                if (isPolling) {
                    CircularProgressIndicator(
                        modifier = Modifier.size(18.dp),
                        strokeWidth = 2.dp
                    )
                } else {
                    Icon(
                        Icons.Default.Refresh,
                        contentDescription = "Refresh listener counts",
                        modifier = Modifier.size(20.dp)
                    )
                }
            }
        }
        if (hiddenCount > 0) {
            Spacer(modifier = Modifier.weight(1f))
            TextButton(onClick = onToggleShowHidden) {
                Text(
                    text = if (showHidden) "Show visible" else "Show $hiddenCount hidden",
                    style = MaterialTheme.typography.labelSmall
                )
            }
        }
    }
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun StationRow(
    station: Station,
    isNowPlaying: Boolean,
    showListeners: Boolean,
    isBuiltIn: Boolean,
    isHiddenView: Boolean,
    hasStreams: Boolean,
    onPlay: () -> Unit,
    onToggleStar: () -> Unit,
    onEdit: () -> Unit,
    onDelete: () -> Unit,
    onToggleHidden: () -> Unit,
    onQuality: () -> Unit,
    modifier: Modifier = Modifier
) {
    var showMenu by remember { mutableStateOf(false) }
    val rowAlpha = if (isHiddenView) 0.5f else 1f

    Box(modifier = modifier.fillMaxWidth()) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .alpha(rowAlpha)
                .combinedClickable(
                    onClick = onPlay,
                    onLongClick = { showMenu = true }
                )
                .padding(vertical = 4.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            IconButton(
                onClick = onToggleStar,
                modifier = Modifier.size(36.dp)
            ) {
                Icon(
                    imageVector = if (station.starred) Icons.Filled.Star else Icons.Outlined.Star,
                    contentDescription = if (station.starred) "Unstar" else "Star",
                    tint = if (station.starred) MaterialTheme.colorScheme.primary
                           else MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.4f)
                )
            }
            Spacer(modifier = Modifier.width(8.dp))
            if (station.defaultArtworkUrl != null) {
                AsyncImage(
                    model = station.defaultArtworkUrl,
                    contentDescription = null,
                    modifier = Modifier
                        .size(36.dp)
                        .clip(CircleShape)
                        .background(MaterialTheme.colorScheme.surfaceVariant, CircleShape)
                )
                Spacer(modifier = Modifier.width(8.dp))
            }
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = station.name,
                    style = MaterialTheme.typography.bodyLarge,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis
                )
                if (isNowPlaying) {
                    Text(
                        text = "Now playing",
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.primary
                    )
                }
            }
            if (showListeners && station.listenerCount > 0) {
                Text(
                    text = "${station.listenerCount}",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant
                )
                Spacer(modifier = Modifier.width(8.dp))
            }
            if (isNowPlaying) {
                Icon(
                    Icons.Default.PlayArrow,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.primary,
                    modifier = Modifier.size(24.dp)
                )
                Spacer(modifier = Modifier.width(4.dp))
            }
        }
        DropdownMenu(
            expanded = showMenu,
            onDismissRequest = { showMenu = false }
        ) {
            if (hasStreams && !isHiddenView) {
                DropdownMenuItem(
                    text = { Text("Quality") },
                    onClick = {
                        showMenu = false
                        onQuality()
                    }
                )
            }
            if (isHiddenView) {
                DropdownMenuItem(
                    text = { Text("Unhide") },
                    onClick = {
                        showMenu = false
                        onToggleHidden()
                    }
                )
            } else {
                DropdownMenuItem(
                    text = { Text("Hide") },
                    onClick = {
                        showMenu = false
                        onToggleHidden()
                    }
                )
            }
            if (!isBuiltIn && !isHiddenView) {
                DropdownMenuItem(
                    text = { Text("Edit") },
                    onClick = {
                        showMenu = false
                        onEdit()
                    }
                )
                DropdownMenuItem(
                    text = { Text("Delete") },
                    onClick = {
                        showMenu = false
                        onDelete()
                    }
                )
            }
        }
    }
}
