package com.anypreta.bountyboard.ui.profile

import android.net.Uri
import android.provider.OpenableColumns
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import kotlinx.coroutines.flow.first
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.anypreta.bountyboard.data.AppContainer
import com.anypreta.bountyboard.data.model.Contact
import com.anypreta.bountyboard.data.model.User
import com.anypreta.bountyboard.data.net.ProfilePatchBody
import com.anypreta.bountyboard.data.net.ProfileSettingsPatch
import com.anypreta.bountyboard.di.LocalAppContainer
import com.anypreta.bountyboard.di.containerVMFactory
import com.anypreta.bountyboard.ui.components.BBAvatar
import com.anypreta.bountyboard.ui.components.BBBadge
import com.anypreta.bountyboard.ui.components.BBButton
import com.anypreta.bountyboard.ui.components.BBButtonStyle
import com.anypreta.bountyboard.ui.components.BBCard
import com.anypreta.bountyboard.ui.components.BBTextField
import com.anypreta.bountyboard.ui.components.ConfirmDialog
import com.anypreta.bountyboard.ui.components.FilterPill
import com.anypreta.bountyboard.ui.components.Hairline
import com.anypreta.bountyboard.ui.components.MessageBox
import com.anypreta.bountyboard.ui.components.MessageKind
import com.anypreta.bountyboard.ui.components.ScreenState
import com.anypreta.bountyboard.ui.components.SectionLabel
import com.anypreta.bountyboard.ui.theme.BB
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody

private val THEMES = listOf(
    "light" to "Light",
    "dark" to "Dark",
    "neon" to "Neon",
    "terminal" to "Terminal",
    "blueprint" to "Blueprint",
    "sunset" to "Sunset",
)

class ProfileViewModel(private val container: AppContainer) : ViewModel() {

    var loading by mutableStateOf(true)
        private set
    var error by mutableStateOf<String?>(null)
        private set
    var user by mutableStateOf<User?>(null)
        private set

    var actionLoading by mutableStateOf(false)
        private set
    var actionError by mutableStateOf<String?>(null)
        private set
    var actionInfo by mutableStateOf<String?>(null)
        private set
    var pushEnabled by mutableStateOf(true)
        private set

    init {
        load()
        viewModelScope.launch { pushEnabled = container.settings.pushEnabled.first() }
    }

    fun setPush(enabled: Boolean) {
        pushEnabled = enabled
        viewModelScope.launch {
            container.settings.setPushEnabled(enabled)
            if (enabled) {
                container.schedulePush()
                container.startLiveService()
            } else {
                container.cancelPush()
                container.stopLiveService()
            }
        }
    }

    fun load() {
        loading = true; error = null
        viewModelScope.launch {
            try {
                user = container.repo.call { profile() }.user
            } catch (e: Exception) {
                error = e.message
            } finally {
                loading = false
            }
        }
    }

    fun uploadAvatar(bytes: ByteArray, name: String, mime: String) {
        actionLoading = true; actionError = null; actionInfo = null
        viewModelScope.launch {
            try {
                val body = bytes.toRequestBody(mime.toMediaTypeOrNull())
                val part = MultipartBody.Part.createFormData("file", name, body)
                container.repo.call { uploadAvatar(part) }
                val updated = container.repo.call { profile() }.user
                user = updated
                container.session.setSession(updated, false)
                actionInfo = "Photo updated."
            } catch (e: Exception) {
                actionError = e.message
            } finally {
                actionLoading = false
            }
        }
    }

    fun save(name: String, bio: String, phone: String, location: String, theme: String, optOut: Boolean) {
        val current = user ?: return
        actionLoading = true; actionError = null; actionInfo = null
        viewModelScope.launch {
            try {
                val contact = Contact(
                    phone = phone.ifBlank { null },
                    location = location.ifBlank { null },
                    links = current.contact?.links,
                )
                val body = ProfilePatchBody(
                    name = name.trim(),
                    bio = bio,
                    contact = contact,
                    settings = ProfileSettingsPatch(theme = theme, leaderboardOptOut = optOut),
                    version = current.version,
                )
                val updated = container.repo.call { patchProfile(body) }.user
                user = updated
                container.session.setSession(updated, false)
                actionInfo = "Profile saved."
            } catch (e: Exception) {
                actionError = e.message
            } finally {
                actionLoading = false
            }
        }
    }

    fun applyTheme(themeId: String) {
        viewModelScope.launch {
            container.settings.setTheme(themeId)
        }
    }

    fun logoutAll(onDone: () -> Unit) {
        actionLoading = true; actionError = null
        viewModelScope.launch {
            try {
                container.repo.call { logoutAll() }
                container.session.clear()
                container.cookieJar.clear()
                onDone()
            } catch (e: Exception) {
                actionError = e.message
            } finally {
                actionLoading = false
            }
        }
    }
}

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun ProfileScreen() {
    val container = LocalAppContainer.current
    val vm: ProfileViewModel = viewModel(factory = containerVMFactory(container) { ProfileViewModel(it) })
    val ctx = LocalContext.current
    val p = BB.colors

    var name by remember { mutableStateOf("") }
    var bio by remember { mutableStateOf("") }
    var phone by remember { mutableStateOf("") }
    var location by remember { mutableStateOf("") }
    var theme by remember { mutableStateOf("light") }
    var optOut by remember { mutableStateOf(false) }
    var initialized by remember { mutableStateOf(false) }
    var confirmLogout by remember { mutableStateOf(false) }

    LaunchedEffect(vm.user) {
        val u = vm.user
        if (u != null && !initialized) {
            name = u.name
            bio = u.bio ?: ""
            phone = u.contact?.phone ?: ""
            location = u.contact?.location ?: ""
            theme = u.settings?.theme ?: "light"
            optOut = u.settings?.leaderboardOptOut ?: false
            initialized = true
        }
    }

    val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
        if (uri != null) {
            val bytes = ctx.contentResolver.openInputStream(uri)?.use { it.readBytes() }
            if (bytes != null) {
                val fileName = queryName(ctx, uri)
                val mime = ctx.contentResolver.getType(uri) ?: "application/octet-stream"
                vm.uploadAvatar(bytes, fileName, mime)
            }
        }
    }

    ScreenState(loading = vm.loading, error = vm.error, onRetry = { vm.load() }) {
        val user = vm.user ?: return@ScreenState

        Column(
            Modifier
                .fillMaxWidth()
                .verticalScroll(rememberScrollState())
                .padding(16.dp),
            verticalArrangement = Arrangement.spacedBy(14.dp),
        ) {
            // Avatar
            Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(10.dp)) {
                BBAvatar(user.name, user.avatarFileId, size = 96.dp)
                BBButton(
                    "Change photo",
                    onClick = { launcher.launch("image/*") },
                    style = BBButtonStyle.Default,
                    small = true,
                    loading = vm.actionLoading,
                )
            }

            vm.actionError?.let { MessageBox(it, MessageKind.Error) }
            vm.actionInfo?.let { MessageBox(it, MessageKind.Ok) }

            // Identity
            BBCard(modifier = Modifier.fillMaxWidth()) {
                Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
                    SectionLabel("Account")
                    Text(user.email, style = MaterialTheme.typography.bodyLarge, color = p.text)
                    Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
                        if (user.roles.admin) BBBadge("Admin", color = p.accent)
                        if (user.roles.consultant) BBBadge("Consultant", color = p.ok)
                        if (user.roles.developer) BBBadge("Developer", color = p.muted)
                    }
                }
            }

            // Editable fields
            BBCard(modifier = Modifier.fillMaxWidth()) {
                Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                    SectionLabel("Profile")
                    BBTextField(name, { name = it }, "Name", modifier = Modifier.fillMaxWidth())
                    BBTextField(bio, { bio = it }, "Bio", singleLine = false, minLines = 3, modifier = Modifier.fillMaxWidth())
                    BBTextField(phone, { phone = it }, "Phone", modifier = Modifier.fillMaxWidth())
                    BBTextField(location, { location = it }, "Location", modifier = Modifier.fillMaxWidth())
                }
            }

            // Theme picker
            BBCard(modifier = Modifier.fillMaxWidth()) {
                Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
                    SectionLabel("Theme")
                    FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
                        THEMES.forEach { (id, label) ->
                            FilterPill(
                                text = if (theme == id) "● $label" else label,
                                showCaret = false,
                                onClick = {
                                    theme = id
                                    vm.applyTheme(id)
                                },
                            )
                        }
                    }
                    Hairline()
                    Row(
                        Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween,
                    ) {
                        Text("Hide me from the leaderboard", style = MaterialTheme.typography.bodyMedium, color = p.text)
                        Switch(
                            checked = optOut,
                            onCheckedChange = { optOut = it },
                            colors = SwitchDefaults.colors(
                                checkedThumbColor = p.onAccent,
                                checkedTrackColor = p.accent,
                                uncheckedTrackColor = p.surface2,
                                uncheckedBorderColor = p.border,
                            ),
                        )
                    }
                    Hairline()
                    Row(
                        Modifier.fillMaxWidth(),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.SpaceBetween,
                    ) {
                        Column(Modifier.weight(1f)) {
                            Text("Push notifications", style = MaterialTheme.typography.bodyMedium, color = p.text)
                            Text("Background alerts & messages (~15 min)", style = MaterialTheme.typography.labelSmall, color = p.muted)
                        }
                        Switch(
                            checked = vm.pushEnabled,
                            onCheckedChange = { vm.setPush(it) },
                            colors = SwitchDefaults.colors(
                                checkedThumbColor = p.onAccent,
                                checkedTrackColor = p.accent,
                                uncheckedTrackColor = p.surface2,
                                uncheckedBorderColor = p.border,
                            ),
                        )
                    }
                }
            }

            BBButton(
                "Save",
                onClick = { vm.save(name, bio, phone, location, theme, optOut) },
                style = BBButtonStyle.Primary,
                loading = vm.actionLoading,
                modifier = Modifier.fillMaxWidth(),
            )

            Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
                BBButton(
                    "Sign out everywhere",
                    onClick = { confirmLogout = true },
                    style = BBButtonStyle.Danger,
                )
            }

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

    if (confirmLogout) {
        ConfirmDialog(
            title = "Sign out everywhere",
            message = "This revokes every active session on all devices. You'll need to sign in again.",
            confirmText = "Sign out",
            danger = true,
            onConfirm = { confirmLogout = false; vm.logoutAll {} },
            onDismiss = { confirmLogout = false },
        )
    }
}

private fun queryName(ctx: android.content.Context, uri: Uri): String {
    var name = "upload"
    try {
        ctx.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
            val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            if (idx >= 0 && cursor.moveToFirst()) {
                cursor.getString(idx)?.let { if (it.isNotBlank()) name = it }
            }
        }
    } catch (_: Exception) {
    }
    return name
}
