/*
 * Copyright 2025 - 2026 PICO. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.pico.spatialui.sample.pages

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
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.layout.wrapContentHeight
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.pico.spatial.ui.design.Badge
import com.pico.spatial.ui.design.BadgeDefaults
import com.pico.spatial.ui.design.Button
import com.pico.spatial.ui.design.ButtonDefaults
import com.pico.spatial.ui.design.Icon
import com.pico.spatial.ui.design.IconButton
import com.pico.spatial.ui.design.IconButtonDefaults
import com.pico.spatial.ui.design.PageControl
import com.pico.spatial.ui.design.PageControlDefaults
import com.pico.spatial.ui.design.PicoTheme
import com.pico.spatial.ui.design.Text
import com.pico.spatial.ui.design.windows.CoachmarkBox
import com.pico.spatial.ui.design.windows.CoachmarkDefaults
import com.pico.spatial.ui.design.windows.CoachmarkDirection
import com.pico.spatial.ui.design.windows.RichCoachmark
import com.pico.spatial.ui.design.windows.Subwindow
import com.pico.spatial.ui.foundation.hover.spatialHoverEffect
import com.pico.spatial.ui.foundation.vibrant.Vibrant
import com.pico.spatial.ui.foundation.vibrant.withVibrant
import com.pico.spatial.ui.graphics.Vibrant
import com.pico.spatialui.sample.R
import com.pico.spatialui.sample.model.CardData
import com.pico.spatialui.sample.model.UserData
import com.pico.spatialui.sample.viewmodel.FeedsViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Composable
fun RecommendedUser(
    userData: UserData,
    modifier: Modifier = Modifier,
    clickHandler: () -> Unit,
) {
    Row(
        modifier =
            modifier.clip(RoundedCornerShape(8.dp)).spatialHoverEffect().clickable {
                clickHandler()
            },
        verticalAlignment = Alignment.CenterVertically
    ) {
        Image(
            painter = painterResource(userData.imageId),
            contentDescription = null,
            modifier =
                Modifier.padding(12.dp)
                    .size(72.dp)
                    .clip(CircleShape)
                    .background(colorResource(userData.bgId))
        )

        Spacer(Modifier.width(4.dp))

        Column(modifier = Modifier.weight(1f)) {
            Row(verticalAlignment = Alignment.CenterVertically) {
                Text(
                    stringResource(userData.nameRes),
                    style = PicoTheme.typography.titleMedium,
                    modifier = Modifier.wrapContentHeight(Alignment.CenterVertically),
                    color = PicoTheme.colorTokens.LabelPrimary,
                )
                if (userData.hot) {
                    Badge(
                        modifier = Modifier.padding(start = 4.dp).size(18.dp),
                        badgeColor = BadgeDefaults.badgeColors(Color(0xFFFF794C))
                    ) {
                        Icon(
                            painter = painterResource(R.drawable.fire),
                            contentDescription = null,
                            tint = Color.Yellow
                        )
                    }
                }
            }

            Text(
                stringResource(userData.descriptionRes),
                style = PicoTheme.typography.bodySmall,
                color = PicoTheme.colorTokens.LabelTertiaryAlpha,
                maxLines = 1,
                overflow = TextOverflow.Ellipsis
            )
        }

        Spacer(Modifier.width(8.dp))

        Button(
            onClick = {},
            size = ButtonDefaults.Min,
            colors =
                ButtonDefaults.buttonColors(
                    contentColor = Color.Vibrant.withVibrant(Vibrant.Darkest),
                    containerColor = Color.Vibrant.withVibrant(Vibrant.Neutral)
                )
        ) {
            Text(stringResource(R.string.sui_sample_follow))
        }

        Spacer(Modifier.width(12.dp))
    }
}

@Composable
fun <T> FixedGrid(
    rowCount: Int,
    columnCount: Int,
    contentList: List<T>,
    modifier: Modifier = Modifier,
    itemContent: @Composable (T) -> Unit
) {
    require(columnCount * rowCount <= contentList.size) {
        "List size must be at least [columnCount * rowCount]"
    }

    Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(20.dp)) {
        repeat(rowCount) { rowIndex ->
            Row(
                horizontalArrangement = Arrangement.spacedBy(20.dp),
                modifier = Modifier.weight(1f)
            ) {
                repeat(columnCount) { colIndex ->
                    val index = rowIndex * columnCount + colIndex

                    Box(
                        modifier = Modifier.weight(1f).fillMaxHeight(),
                        contentAlignment = Alignment.Center
                    ) {
                        itemContent(contentList[index])
                    }
                }
            }
        }
    }
}

@Composable
fun Banner(
    modifier: Modifier = Modifier,
    imageItems: List<CardData>,
    maxDisplayCount: Int = 9,
    autoLoop: Boolean = true,
    loopDuration: Long = 3000L,
    onNavigateToDetail: (String) -> Unit
) {
    Box(modifier = modifier) {
        if (imageItems.isEmpty()) return@Box

        key(imageItems) {
            val totalPages = Int.MAX_VALUE
            val initialPage = totalPages / 2
            val pagerState =
                rememberPagerState(initialPage = initialPage, pageCount = { totalPages })

            if (autoLoop) {
                LaunchedEffect(pagerState) {
                    while (true) {
                        delay(loopDuration)
                        if (!pagerState.isScrollInProgress) {
                            val nextPage = pagerState.currentPage + 1
                            pagerState.animateScrollToPage(nextPage)
                        }
                    }
                }
            }

            HorizontalPager(
                state = pagerState,
                pageSpacing = 10.dp,
            ) { pageIndex ->
                val realIndex = pageIndex % imageItems.size
                AsyncImage(
                    model = imageItems[realIndex].imageId,
                    modifier =
                        Modifier.fillMaxSize()
                            .clip(RoundedCornerShape(8.dp))
                            .spatialHoverEffect()
                            .clickable { onNavigateToDetail("${imageItems[realIndex].imageId}") },
                    contentScale = ContentScale.Crop,
                    contentDescription = imageItems[realIndex].imageDescription
                )
            }

            val scope = rememberCoroutineScope()
            PageControl(
                modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 12.dp),
                currentIndex = pagerState.currentPage % imageItems.size,
                onClickAction = { index ->
                    scope.launch {
                        val targetPage =
                            pagerState.currentPage +
                                (index - (pagerState.currentPage % imageItems.size))
                        pagerState.animateScrollToPage(targetPage)
                    }
                },
                colors =
                    PageControlDefaults.pageControlColors().copy(normalColor = Color(0x4dffffff)),
                maxDisplayCount = maxDisplayCount,
                totalDots = imageItems.size,
                pageControlSpec = PageControlDefaults.Spec.copy(dotSpace = 6.dp)
            )
        }
    }
}

@Composable
fun UserDetail(userData: UserData, closeHandler: () -> Unit) {
    Subwindow {
        Column(modifier = Modifier.fillMaxSize().clip(RoundedCornerShape(16.dp))) {
            Spacer(Modifier.height(24.dp))

            AsyncImage(
                model = R.drawable.img_subwindow_bg_new,
                contentDescription = null,
                modifier = Modifier.fillMaxWidth().height(511.dp),
                contentScale = ContentScale.Crop
            )

            Text(
                text = stringResource(userData.nameRes),
                modifier = Modifier.padding(horizontal = 32.dp),
                style = PicoTheme.typography.headlineLarge
            )

            Spacer(Modifier.height(12.dp))

            Text(
                text = stringResource(userData.descriptionRes),
                modifier = Modifier.padding(horizontal = 32.dp),
                style = PicoTheme.typography.bodyMedium
            )

            Spacer(Modifier.weight(1f))

            Button(
                modifier =
                    Modifier.fillMaxWidth()
                        .padding(horizontal = 32.dp)
                        .align(Alignment.CenterHorizontally),
                onClick = {}
            ) {
                Text(
                    text = stringResource(R.string.sui_sample_follow),
                    style = PicoTheme.typography.titleMedium
                )
            }

            Spacer(Modifier.height(32.dp))
        }

        IconButton(
            onClick = closeHandler,
            size = IconButtonDefaults.iconButtonSize(48.dp),
            modifier = Modifier.padding(start = 24.dp, top = 24.dp),
            colors =
                ButtonDefaults.buttonColors(
                    contentColor = Color.Vibrant.withVibrant(Vibrant.Darkest),
                    containerColor = Color.Vibrant.withVibrant(Vibrant.Neutral)
                ),
        ) {
            Icon(painter = painterResource(id = R.drawable.cancel), contentDescription = null)
        }
    }
}

@Composable
fun PageTitleWithCoachMark(modifier: Modifier = Modifier) {
    var showCoachMark by rememberSaveable { mutableStateOf(true) }

    CoachmarkBox(
        showCoachmark = showCoachMark,
        direction = CoachmarkDirection.Below,
        modifier = modifier,
        coachmark = {
            RichCoachmark(
                content = {
                    Text(
                        text = stringResource(R.string.sui_sample_component_usage_coach_mark),
                        style = PicoTheme.typography.bodyLarge
                    )
                },
                buttons = {
                    CoachmarkDefaults.CoachmarkButton(onClick = { showCoachMark = false }) {
                        Text(
                            text = stringResource(R.string.sui_sample_i_known),
                            style = PicoTheme.typography.labelMedium,
                        )
                    }
                }
            )
        }
    ) {
        Text(
            text = stringResource(R.string.sui_sample_component_usage_sample),
            style = PicoTheme.typography.headlineLarge,
            color = Color.Vibrant.withVibrant(Vibrant.UltraDark)
        )
    }
}

@Composable
fun FeedsPage(feedsViewModel: FeedsViewModel = viewModel(), onNavigateToDetail: (String) -> Unit) {
    Box(modifier = Modifier.fillMaxSize()) {
        var selectedUser by remember { mutableStateOf<UserData?>(null) }

        Column(modifier = Modifier.fillMaxSize().padding(horizontal = 32.dp)) {
            PageTitleWithCoachMark(
                modifier = Modifier.padding(vertical = 33.dp).align(Alignment.CenterHorizontally)
            )

            val columnsCount = 4
            val cardList by feedsViewModel.cardList.collectAsStateWithLifecycle()
            LazyVerticalGrid(
                columns = GridCells.Fixed(columnsCount),
                modifier = Modifier.fillMaxWidth().weight(1f),
                contentPadding = PaddingValues(bottom = 32.dp),
                verticalArrangement = Arrangement.spacedBy(20.dp),
                horizontalArrangement = Arrangement.spacedBy(20.dp)
            ) {
                // the banner and the fixed 2 * 2 grid of cards.
                item(span = { GridItemSpan(columnsCount) }) {
                    Row(
                        modifier = Modifier.fillMaxWidth().height(344.dp),
                        horizontalArrangement = Arrangement.spacedBy(20.dp)
                    ) {
                        val bannerCardList by
                            feedsViewModel.bannerCardList.collectAsStateWithLifecycle()
                        Banner(
                            modifier =
                                Modifier.fillMaxHeight().weight(1f).clip(RoundedCornerShape(8.dp)),
                            imageItems = bannerCardList,
                            maxDisplayCount = 8,
                            onNavigateToDetail = onNavigateToDetail
                        )

                        val fixedGridCardList by
                            feedsViewModel.fixedGridCardList.collectAsStateWithLifecycle()
                        FixedGrid(
                            rowCount = 2,
                            columnCount = 2,
                            contentList = fixedGridCardList,
                            modifier = Modifier.fillMaxHeight().weight(1f)
                        ) { data ->
                            AsyncImage(
                                model = data.imageId,
                                contentDescription = data.imageDescription,
                                modifier =
                                    Modifier.fillMaxSize()
                                        .clip(RoundedCornerShape(8.dp))
                                        .spatialHoverEffect()
                                        .clickable { onNavigateToDetail("${data.imageId}") },
                                contentScale = ContentScale.Crop
                            )
                        }
                    }
                }

                // the three recommended users.
                item(span = { GridItemSpan(columnsCount) }) {
                    val userList by feedsViewModel.userList.collectAsStateWithLifecycle()
                    Row(
                        modifier = Modifier.fillMaxWidth(),
                        horizontalArrangement = Arrangement.spacedBy(16.dp)
                    ) {
                        userList.take(3).forEach { userData ->
                            RecommendedUser(userData = userData, modifier = Modifier.weight(1f)) {
                                selectedUser = userData
                            }
                        }
                    }
                }

                // the infinite grid of cards.
                val ratio = 289f / 385f
                items(items = cardList, key = { it.id }) { cardData ->
                    AsyncImage(
                        model = cardData.imageId,
                        modifier =
                            Modifier.fillMaxWidth()
                                .aspectRatio(ratio = ratio)
                                .clip(RoundedCornerShape(8.dp))
                                .spatialHoverEffect()
                                .clickable { onNavigateToDetail("${cardData.imageId}") },
                        contentScale = ContentScale.Crop,
                        contentDescription = cardData.imageDescription
                    )
                }
            }
        }

        selectedUser?.let { userData -> UserDetail(userData) { selectedUser = null } }
    }
}

@Preview(showBackground = false, widthDp = 1280, heightDp = 720)
@Composable
fun FeedsPagePreview() {
    PicoTheme { FeedsPage(viewModel()) {} }
}
