OrderDetailComponents.kt

/*
 * This file is part of GNU Taler
 * (C) 2026 Taler Systems S.A.
 *
 * GNU Taler is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3, or (at your option) any later version.
 *
 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

package net.taler.lib.android.order

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.FlowRowScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp

@Composable
public fun OrderDetailHeader(
    merchantName: String,
    total: String?,
    leadingIcon: ImageVector,
    wide: Boolean,
    orderIdDisplay: @Composable (compact: Boolean) -> Unit,
    modifier: Modifier = Modifier,
    statusAndMetadata: @Composable FlowRowScope.() -> Unit = {},
    trailingActions: @Composable RowScope.() -> Unit = {},
    footer: @Composable ColumnScope.() -> Unit = {},
) {
    OutlinedCard(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.surface),
        border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
    ) {
        Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(14.dp)) {
            Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
                OrderDetailIcon(leadingIcon)
                Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
                    Text(merchantName, style = MaterialTheme.typography.titleMedium)
                    total?.let { Text(it, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Medium) }
                }
                if (wide) {
                    androidx.compose.foundation.layout.Box(Modifier.weight(1.2f)) { orderIdDisplay(true) }
                }
                trailingActions()
            }
            FlowRow(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
                statusAndMetadata()
            }
            if (!wide) orderIdDisplay(false)
            footer()
        }
    }
}

@Composable
public fun OrderDetailStatusBadge(
    label: String,
    containerColor: Color = MaterialTheme.colorScheme.secondaryContainer,
    contentColor: Color = MaterialTheme.colorScheme.onSecondaryContainer,
    modifier: Modifier = Modifier,
) {
    Surface(
        modifier = modifier,
        color = containerColor,
        contentColor = contentColor,
        shape = MaterialTheme.shapes.small,
    ) {
        Text(label, modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
            style = MaterialTheme.typography.labelLarge)
    }
}

@Composable
public fun OrderDetailBalanceStrip(
    label: String,
    amount: String,
    modifier: Modifier = Modifier,
    containerColor: Color = MaterialTheme.colorScheme.errorContainer,
    contentColor: Color = MaterialTheme.colorScheme.onErrorContainer,
) {
    Surface(modifier = modifier.fillMaxWidth(), shape = RoundedCornerShape(12.dp),
        color = containerColor, contentColor = contentColor) {
        FlowRow(
            modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp, vertical = 12.dp),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalArrangement = Arrangement.spacedBy(4.dp),
        ) {
            Text(label, style = MaterialTheme.typography.titleMedium)
            Text(amount, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.SemiBold)
        }
    }
}

@Composable
public fun OrderDetailSection(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) {
    OutlinedCard(
        modifier = modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        colors = CardDefaults.outlinedCardColors(containerColor = MaterialTheme.colorScheme.surface),
        border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant),
    ) {
        Column(Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) {
            Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
                OrderDetailIcon(icon)
                Text(title, style = MaterialTheme.typography.titleMedium)
            }
            content()
        }
    }
}

@Composable
public fun OrderDetailIcon(icon: ImageVector, modifier: Modifier = Modifier) {
    Surface(modifier = modifier, shape = CircleShape, color = MaterialTheme.colorScheme.secondaryContainer) {
        Icon(icon, contentDescription = null, modifier = Modifier.padding(10.dp).size(22.dp),
            tint = MaterialTheme.colorScheme.secondary)
    }
}

@Composable
public fun OrderDetailValue(
    label: String,
    value: String,
    icon: ImageVector? = null,
    modifier: Modifier = Modifier,
) {
    Row(modifier = modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
        icon?.let { Icon(it, contentDescription = null, modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) }
        Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
            Text(label, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
            SelectionContainer { Text(value, style = MaterialTheme.typography.bodyMedium) }
        }
    }
}

/** The caller supplies localized action labels and open/copy callbacks. */
@Composable
public fun OrderDetailCopyableValue(
    label: String,
    value: String,
    modifier: Modifier = Modifier,
    isLink: Boolean = false,
    compactAction: Boolean = false,
    openAction: @Composable RowScope.() -> Unit = {},
    copyAction: @Composable RowScope.() -> Unit,
) {
    Column(modifier) {
        Text(label, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
        Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
            SelectionContainer(if (compactAction) Modifier.weight(1f, fill = false) else Modifier.weight(1f)) {
                Text(value, style = MaterialTheme.typography.bodyMedium,
                    color = if (isLink) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface)
            }
            if (isLink) openAction()
            copyAction()
        }
    }
}

@Composable
public fun OrderDetailSummaryBlock(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) = OrderDetailSection(icon, title, modifier, content)

@Composable
public fun OrderDetailProductsBlock(
    icon: ImageVector,
    title: String,
    productCount: Int,
    emptyMessage: String,
    totalLabel: String?,
    total: String?,
    modifier: Modifier = Modifier,
    product: @Composable ColumnScope.(index: Int) -> Unit,
) {
    OrderDetailSection(icon, title, modifier) {
        if (productCount == 0) Text(emptyMessage, style = MaterialTheme.typography.bodyMedium)
        repeat(productCount) { index ->
            if (index > 0) HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
            product(index)
        }
        if (total != null && totalLabel != null) {
            HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
            FlowRow(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween,
                verticalArrangement = Arrangement.spacedBy(4.dp)) {
                Text(totalLabel, fontWeight = FontWeight.Medium)
                Text(total, fontWeight = FontWeight.Medium)
            }
        }
    }
}

@Composable
public fun OrderDetailPaymentsBlock(
    icon: ImageVector,
    title: String,
    paymentCount: Int,
    modifier: Modifier = Modifier,
    payment: @Composable ColumnScope.(index: Int) -> Unit,
) {
    OrderDetailSection(icon, title, modifier) {
        repeat(paymentCount) { index ->
            if (index > 0) HorizontalDivider(Modifier.padding(vertical = 4.dp), color = MaterialTheme.colorScheme.outlineVariant)
            payment(index)
        }
    }
}

@Composable
public fun OrderDetailProductRow(
    name: String,
    description: String?,
    quantity: String,
    price: String?,
    modifier: Modifier = Modifier,
    thumbnail: (@Composable () -> Unit)? = null,
    unitPrice: String? = null,
) {
    Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
        thumbnail?.invoke()
        Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
            Text(name, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Medium)
            description?.takeIf { it.isNotBlank() && it != name }?.let {
                Text(it, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
            }
            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp),
                verticalAlignment = Alignment.Bottom) {
                Text(if (unitPrice == null) quantity else "$quantity × $unitPrice",
                    modifier = Modifier.weight(1f),
                    style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
                price?.let { Text(it, modifier = Modifier.widthIn(max = 180.dp),
                    style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.End) }
            }
        }
    }
}

@Composable
public fun OrderDetailPaymentRow(
    amount: String,
    method: String? = null,
    reference: String? = null,
    status: String? = null,
    modifier: Modifier = Modifier,
    methodContent: (@Composable ColumnScope.() -> Unit)? = null,
) {
    Row(modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.Top) {
        Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp)) {
            if (methodContent != null) methodContent() else {
                method?.let { Text(it, style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Medium) }
            }
            reference?.let { SelectionContainer { Text(it, style = MaterialTheme.typography.bodySmall) } }
            status?.let { Text(it, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) }
        }
        Text(amount, modifier = Modifier.widthIn(max = 180.dp).align(Alignment.Bottom),
            style = MaterialTheme.typography.bodyMedium, textAlign = TextAlign.End)
    }
}

@Composable
public fun OrderDetailDeliveryBlock(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) = OrderDetailSection(icon, title, modifier, content)

@Composable
public fun OrderDetailReorderBlock(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) = OrderDetailSection(icon, title, modifier, content)

@Composable
public fun OrderDetailAdditionalBlock(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) = OrderDetailSection(icon, title, modifier, content)

@Composable
public fun OrderDetailMerchantBlock(
    icon: ImageVector,
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) = OrderDetailSection(icon, title, modifier, content)