package tk.zwander.common.compose.settings

import android.content.SharedPreferences
import androidx.annotation.ColorInt
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
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.graphics.painter.Painter
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.core.content.edit
import androidx.core.graphics.toColorInt
import com.github.skydoves.colorpicker.compose.*
import tk.zwander.common.compose.components.AnimatedBottomSheet
import tk.zwander.common.compose.util.rememberPreferenceState
import tk.zwander.common.util.prefManager
import tk.zwander.lockscreenwidgets.R

class ColorPickerPreference(
    title: @Composable () -> String,
    summary: @Composable () -> String?,
    key: @Composable () -> String,
    defaultValue: @Composable () -> Int,
    icon: @Composable () -> Painter? = { null },
    enabled: @Composable () -> Boolean = { true },
    visible: @Composable () -> Boolean = { true },
    badge: (@Composable () -> Unit)? = null,
    preferences: SharedPreferences? = null,
) : BasePreference<Int>(
    title = title,
    summary = summary,
    key = key,
    defaultValue = defaultValue,
    icon = icon,
    enabled = enabled,
    visible = visible,
    badge = badge,
    preferences = preferences,
) {
    @Composable
    override fun Render(modifier: Modifier) {
        ColorPickerPreference(
            title = title(),
            summary = summary(),
            key = key(),
            defaultValue = Color(defaultValue()),
            modifier = modifier,
            icon = icon(),
            enabled = enabled(),
            badge = badge,
            preferences = preferences,
        )
    }
}

@Composable
fun ColorPickerPreference(
    title: String,
    summary: String?,
    key: String,
    @ColorInt defaultValue: Color,
    modifier: Modifier = Modifier,
    icon: Painter? = null,
    enabled: Boolean = true,
    badge: (@Composable () -> Unit)? = null,
    preferences: SharedPreferences? = null,
) {
    val context = LocalContext.current
    var value by rememberPreferenceState(
        key = key,
        value = { Color((preferences ?: context.prefManager.prefs).getInt(it, defaultValue.toArgb())) },
        onChanged = { k, v ->
            (preferences ?: context.prefManager.prefs).edit {
                putInt(k, v.toArgb())
            }
        },
    )

    ColorPickerPreference(
        title = title,
        summary = summary,
        color = value,
        onColorChanged = { value = it },
        modifier = modifier,
        icon = icon,
        enabled = enabled,
        defaultValue = defaultValue,
        badge = badge,
    )
}

@Composable
fun ColorPickerPreference(
    title: String,
    summary: String?,
    color: Color,
    onColorChanged: (color: Color) -> Unit,
    defaultValue: Color,
    modifier: Modifier = Modifier,
    icon: Painter? = null,
    enabled: Boolean = true,
    badge: (@Composable () -> Unit)? = null,
) {
    var showingPickerDialog by remember {
        mutableStateOf(false)
    }

    ColorPickerLayout(
        color = color,
        showingPickerDialog = showingPickerDialog,
        onShowingPickerDialogChanged = { showingPickerDialog = it },
        onColorChanged = onColorChanged,
        modifier = modifier,
        initialColor = defaultValue,
    ) { modifier, colorPreview ->
        BasePreferenceLayout(
            title = title,
            summary = summary,
            modifier = modifier,
            icon = icon,
            onClick = { showingPickerDialog = true },
            widget = colorPreview,
            enabled = enabled,
            badge = badge,
        )
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ColorPickerLayout(
    color: Color,
    showingPickerDialog: Boolean,
    onShowingPickerDialogChanged: (Boolean) -> Unit,
    onColorChanged: (color: Color) -> Unit,
    modifier: Modifier = Modifier,
    initialColor: Color = remember { color },
    layout: @Composable (modifier: Modifier, colorPreview: @Composable (modifier: Modifier) -> Unit) -> Unit,
) {
    val bottomSheetState = rememberBottomSheetState(
        initialValue = SheetValue.Hidden,
        enabledValues = [SheetValue.Hidden, SheetValue.Expanded],
    )

    val controller = rememberColorPickerController()
    val currentControllerColor by controller.selectedColor

    var textFieldContents by remember(showingPickerDialog) {
        mutableStateOf(color.toArgb().toHexString())
    }
    var textFieldValid by remember(showingPickerDialog) {
        mutableStateOf(true)
    }
    var initialized by remember(showingPickerDialog) {
        mutableStateOf(false)
    }

    LaunchedEffect(showingPickerDialog) {
        controller.selectByColor(color, false)
        initialized = true
    }

    LaunchedEffect(currentControllerColor) {
        if (initialized) {
            val newColorInt = currentControllerColor.toArgb()
            val currentColorInt = try {
                "#${textFieldContents}".toColorInt()
            } catch (_: IllegalArgumentException) {
                null
            }

            if (newColorInt != currentColorInt) {
                textFieldContents = newColorInt.toHexString()
            }
        }
    }

    LaunchedEffect(textFieldContents) {
        textFieldValid = try {
            val newColor = Color("#${textFieldContents}".toColorInt())
            controller.selectByColor(newColor, false)
            true
        } catch (_: IllegalArgumentException) {
            false
        }
    }

    layout(
        modifier,
    ) {
        Box(
            modifier = Modifier
                .size(48.dp)
                .background(
                    color = color,
                    shape = CircleShape,
                )
                .border(
                    width = 2.dp,
                    color = MaterialTheme.colorScheme.onSurface,
                    shape = CircleShape,
                )
                .then(modifier),
        )
    }

    AnimatedBottomSheet(
        onDismissRequest = { onShowingPickerDialogChanged(false) },
        sheetState = bottomSheetState,
        isVisible = showingPickerDialog,
    ) {
        Column(
            modifier = Modifier
                .fillMaxHeight()
                .fillMaxWidth()
                .verticalScroll(rememberScrollState())
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(8.dp),
        ) {
            HsvColorPicker(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(450.dp),
                controller = controller,
            )

            AlphaSlider(
                controller = controller,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(36.dp),
            )

            BrightnessSlider(
                controller = controller,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(36.dp),
            )

            Spacer(modifier = Modifier.size(8.dp))

            TextField(
                value = textFieldContents,
                onValueChange = {
                    textFieldContents = it.replace(Regex("[^a-fA-F0-9]"), "")
                },
                isError = !textFieldValid,
                textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
                prefix = { Text(text = "#") },
                modifier = Modifier.widthIn(min = 100.dp),
                trailingIcon = {
                    IconButton(
                        onClick = {
                            controller.selectByColor(initialColor, true)
                        },
                    ) {
                        Icon(
                            painter = painterResource(R.drawable.undo),
                            contentDescription = stringResource(R.string.reset),
                        )
                    }
                },
            )

            AlphaTile(
                modifier = Modifier
                    .size(84.dp)
                    .clip(RoundedCornerShape(8.dp))
                    .border(1.dp, LocalContentColor.current, RoundedCornerShape(8.dp)),
                controller = controller,
            )

            Row(
                modifier = Modifier.align(Alignment.End),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp),
            ) {
                TextButton(
                    onClick = { onShowingPickerDialogChanged(false) },
                ) {
                    Text(text = stringResource(R.string.cancel))
                }

                TextButton(
                    onClick = {
                        onShowingPickerDialogChanged(false)
                        onColorChanged(controller.selectedColor.value)
                    },
                    enabled = textFieldValid,
                ) {
                    Text(text = stringResource(R.string.apply))
                }
            }
        }
    }
}
