package com.pixelized.biblib.ui.screen.home.detail

import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.Image
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.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
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.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
import androidx.core.text.toSpannable
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
import coil.request.ImageRequest
import coil.size.Dimension
import com.pixelized.biblib.R
import com.pixelized.biblib.ui.composable.SpannedText
import com.pixelized.biblib.ui.composable.animation.AnimatedDelayer
import com.pixelized.biblib.ui.composable.animation.AnimatedOffset
import com.pixelized.biblib.ui.theme.BibLibTheme
import com.pixelized.biblib.utils.extention.bibLib
import com.pixelized.biblib.utils.extention.placeholder
import java.io.Serializable

@Stable
@Immutable
data class BookDetailUio(
    val id: Int,
    val title: String,
    val authorId: Int?,
    val authors: List<AuthorUio>,
    val rating: Float,
    val language: String,
    val date: String?,
    val seriesId: Int?,
    val series: SeriesUio?,
    val description: String,
    val cover: String,
    val placeHolder: Boolean,
) : Serializable {
    @Stable
    @Immutable
    data class AuthorUio(
        val id: Int,
        val name: String,
    )

    @Stable
    @Immutable
    data class SeriesUio(
        val id: Int,
        val name: String,
        val label: String,
    )

    companion object {
        fun preview() = BookDetailUio(
            id = 90,
            title = "Foundation",
            authorId = null,
            authors = listOf(AuthorUio(id = 0, name = "Asimov")),
            date = "1951",
            seriesId = null,
            series = SeriesUio(id = 0, "Foundation", label = "Foundation - 1"),
            description = "En ce début de treizième millénaire, l'Empire n'a jamais été aussi puissant, aussi étendu à travers toute la galaxie. C'est dans sa capitale, Trantor, que l'éminent savant Hari Seldon invente la psychohistoire, une science nouvelle permettant de prédire l'avenir. Grâce à elle, Seldon prévoit l'effondrement de l'Empire d'ici cinq siècles, suivi d'une ère de ténèbres de trente mille ans. Réduire cette période à mille ans est peut-être possible, à condition de mener à terme son projet : la Fondation, chargée de rassembler toutes les connaissances humaines. Une entreprise visionnaire qui rencontre de nombreux et puissants détracteurs...",
            rating = 4.5f,
            language = "Français",
            cover = "",
            placeHolder = false,
        )
    }
}

@Composable
fun DetailScreenContent(
    modifier: Modifier = Modifier,
    book: BookDetailUio,
    onOpenOnBibLib: () -> Unit,
    onAuthor: (BookDetailUio.AuthorUio) -> Unit,
    onSeries: (BookDetailUio.SeriesUio) -> Unit,
    onSend: () -> Unit,
) {
    val density = LocalDensity.current
    val fabHeight = remember { mutableStateOf(0.dp) }

    AnimatedDelayer(
        targetState = book.id,
    ) {
        Box {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .verticalScroll(rememberScrollState())
                    .padding(all = 16.dp)
                    .systemBarsPadding(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.spacedBy(16.dp)
            ) {
                Column(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    AnimatedOffset {
                        Cover(
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(MaterialTheme.bibLib.dimen.detail.cover),
                            cover = book.cover,
                        )
                    }
                    AnimatedOffset {
                        Text(
                            modifier = Modifier
                                .clickable(onClick = onOpenOnBibLib)
                                .padding(
                                    horizontal = 8.dp,
                                    vertical = 2.dp,
                                ),
                            style = MaterialTheme.bibLib.typography.base.caption,
                            color = MaterialTheme.bibLib.colors.typography.emphasis,
                            text = stringResource(id = R.string.detail_open_on_biblib)
                        )
                    }
                }

                AnimatedOffset {
                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally,
                    ) {
                        Text(
                            style = MaterialTheme.typography.h5,
                            color = MaterialTheme.colors.onSurface,
                            textAlign = TextAlign.Center,
                            text = book.title,
                        )
                        book.series?.let { series ->
                            Text(
                                modifier = Modifier.clickable(onClick = { onSeries(series) }),
                                style = MaterialTheme.typography.body1,
                                color = MaterialTheme.bibLib.colors.typography.emphasis,
                                textAlign = TextAlign.Center,
                                text = series.label,
                            )
                        }
                    }
                }

                AnimatedOffset {
                    Column(
                        horizontalAlignment = Alignment.CenterHorizontally,
                    ) {
                        book.authors.forEach { author ->
                            Text(
                                modifier = Modifier.clickable(onClick = { onAuthor(author) }),
                                fontWeight = FontWeight.Normal,
                                style = MaterialTheme.typography.h6,
                                color = MaterialTheme.bibLib.colors.typography.emphasis,
                                textAlign = TextAlign.Center,
                                text = author.name,
                            )
                        }
                    }
                }

                Row {
                    AnimatedOffset(modifier = Modifier.weight(1f)) {
                        TitleLabel(
                            modifier = Modifier.fillMaxWidth(),
                            title = stringResource(id = R.string.detail_rating),
                            label = book.rating.toString(),
                        )
                    }

                    AnimatedOffset(modifier = Modifier.weight(1f)) {
                        TitleLabel(
                            modifier = Modifier.fillMaxWidth(),
                            title = stringResource(id = R.string.detail_language),
                            label = book.language,
                        )
                    }

                    AnimatedOffset(modifier = Modifier.weight(1f)) {
                        TitleLabel(
                            modifier = Modifier.fillMaxWidth(),
                            title = stringResource(id = R.string.detail_release),
                            label = book.date ?: "-",
                        )
                    }
                }

                AnimatedOffset {
                    SpannedText(
                        modifier = Modifier
                            .fillMaxWidth()
                            .placeholder(
                                shape = MaterialTheme.bibLib.shapes.base.medium,
                                visible = { book.placeHolder },
                            ),
                        style = MaterialTheme.typography.body1,
                        color = MaterialTheme.colors.onSurface,
                        text = HtmlCompat.fromHtml(
                            book.description,
                            HtmlCompat.FROM_HTML_MODE_COMPACT,
                        ).toSpannable(),
                    )
                }

                Spacer(height = fabHeight)
            }

            AnimatedOffset(
                modifier = Modifier
                    .align(Alignment.BottomEnd)
                    .padding(all = 16.dp)
                    .systemBarsPadding()
                    .onSizeChanged { fabHeight.value = with(density) { it.height.toDp() } },
            ) {
                Button(
                    onClick = onSend,
                ) {
                    Icon(imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = "")
                    Spacer(modifier = Modifier.width(4.dp))
                    Text(text = stringResource(id = R.string.action_send))
                }
            }
        }
    }
}

@Composable
private fun Cover(
    modifier: Modifier = Modifier,
    cover: String,
) {
    val painter = rememberAsyncImagePainter(
        model = ImageRequest.Builder(LocalContext.current)
            .data(data = cover)
            .size(
                width = Dimension.Undefined,
                height = Dimension.Pixels(
                    px = with(LocalDensity.current) {
                        MaterialTheme.bibLib.dimen.detail.cover.roundToPx()
                    },
                ),
            )
            .build()
    )

    AnimatedContent(
        targetState = painter.state,
        label = "Cover image animation",
        transitionSpec = { fadeIn() togetherWith fadeOut() }
    ) {
        Box(
            modifier = modifier,
            contentAlignment = Alignment.Center,
        ) {
            when (it) {
                AsyncImagePainter.State.Empty -> {
                    Box(
                        modifier = Modifier
                            .height(MaterialTheme.bibLib.dimen.detail.cover)
                            .aspectRatio(ratio = remember { 1f / 1.5f })
                    )
                }

                is AsyncImagePainter.State.Error -> {
                    Box(
                        modifier = Modifier
                            .height(MaterialTheme.bibLib.dimen.detail.cover)
                            .aspectRatio(ratio = remember { 1f / 1.5f }),
                        contentAlignment = Alignment.Center,
                    ) {
                        Icon(
                            modifier = Modifier.size(64.dp),
                            painter = painterResource(id = R.drawable.ic_no_photography_24),
                            contentDescription = null
                        )
                    }
                }

                is AsyncImagePainter.State.Loading -> {
                    Box(
                        modifier = Modifier
                            .height(MaterialTheme.bibLib.dimen.detail.cover)
                            .aspectRatio(ratio = remember { 1f / 1.5f })
                            .placeholder(
                                shape = MaterialTheme.bibLib.shapes.bookThumbnailCoverLarge,
                                isShimmering = { painter.state is AsyncImagePainter.State.Loading },
                                visible = { true },
                            )
                    )
                }

                is AsyncImagePainter.State.Success -> {
                    Image(
                        modifier = Modifier.height(MaterialTheme.bibLib.dimen.detail.cover),
                        painter = painter,
                        contentScale = ContentScale.FillHeight,
                        contentDescription = null,
                    )
                }
            }
        }
    }
}

@Composable
private fun Spacer(height: State<Dp>) {
    Spacer(modifier = Modifier.height(height = height.value))
}

@Composable
private fun TitleLabel(
    modifier: Modifier = Modifier,
    title: String,
    label: String,
) {
    Column(
        modifier = modifier,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            style = MaterialTheme.typography.body2,
            color = MaterialTheme.colors.onSurface,
            text = title,
        )
        Text(
            style = MaterialTheme.typography.body1,
            fontWeight = FontWeight.Bold,
            color = MaterialTheme.colors.onSurface,
            text = label,
        )
    }
}

@Composable
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_NO, heightDp = 1000)
@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES, heightDp = 1000)
private fun DetailScreenContentPreview() {
    BibLibTheme {
        DetailScreenContent(
            modifier = Modifier
                .verticalScroll(state = rememberScrollState())
                .padding(all = 16.dp),
            book = BookDetailUio.preview(),
            onOpenOnBibLib = { },
            onAuthor = { },
            onSeries = { },
            onSend = { },
        )
    }
}