package com.jerboa.ui.components.drawer

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
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.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.Login
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Bookmarks
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.ExpandLess
import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material.icons.outlined.LocationCity
import androidx.compose.material.icons.outlined.Public
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.mutableStateOf
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.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.lifecycle.viewmodel.compose.viewModel
import com.jerboa.R
import com.jerboa.datatypes.UserViewType
import com.jerboa.datatypes.getDisplayName
import com.jerboa.datatypes.samplePerson
import com.jerboa.db.entity.Account
import com.jerboa.db.entity.AnonAccount
import com.jerboa.db.entity.isAnon
import com.jerboa.db.entity.isReady
import com.jerboa.feat.BlurNSFW
import com.jerboa.model.AccountViewModel
import com.jerboa.model.AccountViewModelFactory
import com.jerboa.ui.components.common.IconAndTextDrawerItem
import com.jerboa.ui.components.common.LargerCircularIcon
import com.jerboa.ui.components.common.PictrsBannerImage
import com.jerboa.ui.components.common.customMarquee
import com.jerboa.ui.components.common.getCurrentAccount
import com.jerboa.ui.components.community.CommunityLinkLarger
import com.jerboa.ui.components.home.NavTab
import com.jerboa.ui.theme.DRAWER_BANNER_SIZE
import com.jerboa.ui.theme.LARGE_PADDING
import com.jerboa.ui.theme.SMALL_PADDING
import com.jerboa.ui.theme.XL_PADDING
import it.vercruysse.lemmyapi.datatypes.Community
import it.vercruysse.lemmyapi.datatypes.CommunityFollowerView
import it.vercruysse.lemmyapi.datatypes.MyUserInfo
import it.vercruysse.lemmyapi.datatypes.Person
import it.vercruysse.lemmyapi.dto.ListingType

@Composable
fun Drawer(
    myUserInfo: MyUserInfo?,
    follows: List<CommunityFollowerView>,
    unreadCount: Long,
    unreadAppCount: Long?,
    unreadReportCount: Long?,
    accountViewModel: AccountViewModel,
    onAddAccount: () -> Unit,
    onSwitchAccountClick: (account: Account) -> Unit,
    onSignOutClick: () -> Unit,
    onSwitchAnon: () -> Unit,
    onClickListingType: (ListingType) -> Unit,
    onCommunityClick: (community: Community) -> Unit,
    onClickSettings: () -> Unit,
    isOpen: Boolean,
    blurNSFW: BlurNSFW,
    showBottomNav: Boolean,
    closeDrawer: () -> Unit,
    onSelectTab: (NavTab) -> Unit,
    userViewType: UserViewType,
) {
    var showAccountAddMode by rememberSaveable { mutableStateOf(false) }

    if (!isOpen) showAccountAddMode = false

    DrawerHeader(
        accountViewModel = accountViewModel,
        myPerson = myUserInfo?.local_user_view?.person,
        showAccountAddMode = showAccountAddMode,
        onClickShowAccountAddMode = { showAccountAddMode = !showAccountAddMode },
        showAvatar = myUserInfo?.local_user_view?.local_user?.show_avatars ?: true,
    )
    // Drawer items
    DrawerContent(
        accountViewModel = accountViewModel,
        follows = follows,
        unreadCount = unreadCount,
        unreadAppCount = unreadAppCount,
        unreadReportCount = unreadReportCount,
        myUserInfo = myUserInfo,
        showAccountAddMode = showAccountAddMode,
        onAddAccount = onAddAccount,
        onSwitchAccountClick = onSwitchAccountClick,
        onSignOutClick = onSignOutClick,
        onClickListingType = onClickListingType,
        onCommunityClick = onCommunityClick,
        onClickSettings = onClickSettings,
        blurNSFW = blurNSFW,
        showBottomNav = showBottomNav,
        closeDrawer = closeDrawer,
        onSelectTab = onSelectTab,
        onSwitchAnon = onSwitchAnon,
        userViewType = userViewType,
    )
}

@Composable
fun DrawerContent(
    showAccountAddMode: Boolean,
    follows: List<CommunityFollowerView>,
    onAddAccount: () -> Unit,
    accountViewModel: AccountViewModel,
    onSwitchAccountClick: (account: Account) -> Unit,
    onSignOutClick: () -> Unit,
    onClickListingType: (ListingType) -> Unit,
    onCommunityClick: (community: Community) -> Unit,
    onClickSettings: () -> Unit,
    myUserInfo: MyUserInfo?,
    unreadCount: Long,
    unreadAppCount: Long?,
    unreadReportCount: Long?,
    blurNSFW: BlurNSFW,
    showBottomNav: Boolean,
    closeDrawer: () -> Unit,
    onSelectTab: (NavTab) -> Unit,
    onSwitchAnon: () -> Unit,
    userViewType: UserViewType,
) {
    AnimatedVisibility(
        visible = showAccountAddMode,
        enter = expandVertically(),
        exit = shrinkVertically(),
    ) {
        HorizontalDivider()
        DrawerAddAccountMode(
            accountViewModel = accountViewModel,
            onAddAccount = onAddAccount,
            onSwitchAccountClick = onSwitchAccountClick,
            onSignOutClick = onSignOutClick,
            onSwitchAnon = onSwitchAnon,
        )
    }

    HorizontalDivider()
    DrawerItemsMain(
        myUserInfo = myUserInfo,
        follows = follows,
        onClickListingType = onClickListingType,
        onCommunityClick = onCommunityClick,
        unreadCount = unreadCount,
        unreadAppCount = unreadAppCount,
        unreadReportCount = unreadReportCount,
        onClickSettings = onClickSettings,
        blurNSFW = blurNSFW,
        showBottomNav = showBottomNav,
        onSelectTab = onSelectTab,
        closeDrawer = closeDrawer,
        userViewType = userViewType,
    )
}

@Composable
fun DrawerItemsMain(
    myUserInfo: MyUserInfo?,
    follows: List<CommunityFollowerView>,
    onClickSettings: () -> Unit,
    onClickListingType: (ListingType) -> Unit,
    onCommunityClick: (community: Community) -> Unit,
    unreadCount: Long,
    unreadAppCount: Long?,
    unreadReportCount: Long?,
    blurNSFW: BlurNSFW,
    showBottomNav: Boolean,
    closeDrawer: () -> Unit,
    onSelectTab: (NavTab) -> Unit,
    userViewType: UserViewType,
) {
    val listState = rememberLazyListState()

    LazyColumn(
        state = listState,
    ) {
        if (follows.isNotEmpty()) {
            item {
                IconAndTextDrawerItem(
                    text = stringResource(R.string.home_subscribed),
                    icon = Icons.Outlined.Bookmarks,
                    onClick = {
                        onClickListingType(ListingType.Subscribed)
                        onSelectTab(NavTab.Home)
                    },
                )
            }
        }
        item {
            IconAndTextDrawerItem(
                text = stringResource(R.string.home_local),
                icon = Icons.Outlined.LocationCity,
                onClick = {
                    onClickListingType(ListingType.Local)
                    onSelectTab(NavTab.Home)
                },
            )
        }
        item {
            IconAndTextDrawerItem(
                text = stringResource(R.string.home_all),
                icon = Icons.Outlined.Public,
                onClick = {
                    onClickListingType(ListingType.All)
                    onSelectTab(NavTab.Home)
                },
            )
        }
        item {
            HorizontalDivider()
        }

        if (!showBottomNav) {
            items(NavTab.getEntries(userViewType)) {
                IconAndTextDrawerItem(
                    text = stringResource(it.textId),
                    icon = it.iconOutlined,
                    onClick = {
                        onSelectTab(it)
                        closeDrawer()
                    },
                    iconBadgeCount = when (it) {
                        NavTab.Inbox -> unreadCount
                        NavTab.RegistrationApplications -> unreadAppCount
                        NavTab.Reports -> unreadReportCount
                        else -> null
                    },
                    contentDescription = stringResource(id = it.contentDescriptionId),
                )
            }

            item(contentType = "divider") {
                HorizontalDivider()
            }
        }
        item("settings") {
            IconAndTextDrawerItem(
                text = stringResource(R.string.home_settings),
                icon = Icons.Outlined.Settings,
                onClick = onClickSettings,
            )
        }
        myUserInfo?.also {
            item(contentType = "divider") {
                HorizontalDivider()
            }
        }

        follows.also { follows ->
            item(contentType = "SubscriptionHeader") {
                Text(
                    text = stringResource(R.string.home_subscriptions),
                    modifier = Modifier.padding(LARGE_PADDING),
                    color = MaterialTheme.colorScheme.outline,
                )
            }
            items(
                follows,
                key = { follow -> follow.community.id },
                contentType = { "CommunityLink" },
            ) { follow ->
                CommunityLinkLarger(
                    community = follow.community,
                    onClick = onCommunityClick,
                    showDefaultIcon = true,
                    showAvatar = true,
                    blurNSFW = blurNSFW,
                )
            }
        }
    }
}

@Preview
@Composable
fun DrawerItemsMainPreview() {
    DrawerItemsMain(
        myUserInfo = null,
        follows = emptyList(),
        onClickListingType = {},
        onCommunityClick = {},
        onClickSettings = {},
        unreadCount = 2,
        unreadReportCount = 5,
        unreadAppCount = null,
        blurNSFW = BlurNSFW.NSFW,
        showBottomNav = false,
        closeDrawer = {},
        onSelectTab = {},
        userViewType = UserViewType.Normal,
    )
}

@Composable
fun DrawerAddAccountMode(
    accountViewModel: AccountViewModel,
    onAddAccount: () -> Unit,
    onSwitchAccountClick: (account: Account) -> Unit,
    onSignOutClick: () -> Unit,
    onSwitchAnon: () -> Unit,
) {
    val allAccounts = accountViewModel.allAccounts.observeAsState(emptyList())
    val accountsWithoutCurrent = allAccounts.value.toMutableList()
    val currentAccount = getCurrentAccount(accountViewModel = accountViewModel)

    accountsWithoutCurrent.remove(currentAccount)

    Column(Modifier.verticalScroll(rememberScrollState())) {
        if (!currentAccount.isAnon()) {
            IconAndTextDrawerItem(
                text = stringResource(R.string.home_sign_out),
                icon = Icons.Outlined.Close,
                onClick = onSignOutClick,
            )

            IconAndTextDrawerItem(
                text = stringResource(R.string.home_switch_anon),
                icon = Icons.AutoMirrored.Outlined.Login,
                onClick = onSwitchAnon,
            )
        }

        accountsWithoutCurrent.forEach {
            IconAndTextDrawerItem(
                text = stringResource(R.string.home_switch_to, it.name, it.instance),
                icon = Icons.AutoMirrored.Outlined.Login,
                onClick = { onSwitchAccountClick(it) },
            )
        }

        IconAndTextDrawerItem(
            text = stringResource(R.string.home_add_account),
            icon = Icons.Outlined.Add,
            onClick = onAddAccount,
        )
    }
}

@Preview
@Composable
fun DrawerAddAccountModePreview() {
    val accountViewModel: AccountViewModel = viewModel(factory = AccountViewModelFactory.Factory)
    DrawerAddAccountMode(
        onAddAccount = {},
        onSignOutClick = {},
        onSwitchAccountClick = {},
        accountViewModel = accountViewModel,
        onSwitchAnon = {},
    )
}

@Composable
fun DrawerHeader(
    accountViewModel: AccountViewModel,
    myPerson: Person?,
    onClickShowAccountAddMode: () -> Unit,
    showAccountAddMode: Boolean = false,
    showAvatar: Boolean,
) {
    val account = getCurrentAccount(accountViewModel)
    val showWarningIcon = !account.isAnon() && !account.isReady()

    val sizeMod =
        Modifier
            .fillMaxWidth()
            .height(DRAWER_BANNER_SIZE)

    Box(
        modifier =
            sizeMod
                .clickable(onClick = onClickShowAccountAddMode),
    ) {
        myPerson?.banner?.also {
            PictrsBannerImage(
                url = it,
            )
        }
        // banner
        Row(
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically,
            modifier =
                sizeMod
                    .padding(XL_PADDING),
        ) {
            if (showWarningIcon) {
                Icon(
                    modifier =
                        Modifier
                            .weight(0.1f)
                            .padding(end = SMALL_PADDING),
                    imageVector = Icons.Outlined.WarningAmber,
                    contentDescription = stringResource(R.string.warning),
                    tint = MaterialTheme.colorScheme.error,
                )
            }
            Box(modifier = Modifier.weight(if (showWarningIcon) 0.8f else 0.9f)) {
                AvatarAndAccountName(account, myPerson, showAvatar)
            }
            Icon(
                modifier = Modifier.weight(0.1f),
                imageVector =
                    if (showAccountAddMode) {
                        Icons.Outlined.ExpandLess
                    } else {
                        Icons.Outlined.ExpandMore
                    },
                contentDescription =
                    if (showAccountAddMode) {
                        stringResource(R.string.moreOptions)
                    } else {
                        stringResource(R.string.lessOptions)
                    },
            )
        }
    }
}

@Composable
fun AvatarAndAccountName(
    account: Account,
    myPerson: Person?,
    showAvatar: Boolean,
) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(SMALL_PADDING),
    ) {
        if (showAvatar) {
            myPerson?.avatar?.also {
                LargerCircularIcon(icon = it)
            }
        }
        Column {
            Text(
                text = myPerson?.getDisplayName() ?: account.name,
                style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier.customMarquee(),
            )
            Text(
                text = if (account.isAnon()) "" else "${account.name}@${account.instance}",
                color = MaterialTheme.colorScheme.tertiary,
                style = MaterialTheme.typography.bodyMedium,
                modifier = Modifier.customMarquee(),
                maxLines = 2,
            )
        }
    }
}

@Preview
@Composable
fun AvatarAndAccountNamePreview() {
    AvatarAndAccountName(account = AnonAccount, myPerson = samplePerson, showAvatar = true)
}

@Preview
@Composable
fun DrawerHeaderPreview() {
    val accountViewModel: AccountViewModel = viewModel(factory = AccountViewModelFactory.Factory)
    DrawerHeader(
        myPerson = samplePerson,
        onClickShowAccountAddMode = {},
        showAvatar = true,
        accountViewModel = accountViewModel,
    )
}
