BuiltInOptions.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.merchantpos.paymentoptions

import android.content.Context
import android.nfc.NfcAdapter

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Payments
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource

import net.taler.merchantpos.R
import net.taler.merchantpos.devices.TalerBleStatus
import net.taler.merchantpos.devices.TalerBluetoothDevice
import net.taler.merchantpos.devices.TalerDevicesContent
import net.taler.merchantpos.devices.TalerUsbDevices
import net.taler.merchantpos.devices.TalerUsbStatus
import net.taler.merchantpos.devices.label

/** Taler is always the last payment of a checkout, so others look it up by id. */
const val TALER_OPTION_ID = "taler"

/**
 * QR payments remain available regardless of NFC or external display status.
 */
class TalerOption(
    private val context: Context,
    private val usb: TalerUsbDevices? = null,
    private val bluetooth: TalerBluetoothDevice? = null,
) : PaymentOption
{
    override val id = TALER_OPTION_ID
    override val nameRes = R.string.payment_option_taler
    override val descriptionRes = R.string.payment_option_taler_description
    override val enabledByDefault = true
    override val alwaysEnabled = true
    override val hasSettings get() = usb != null && bluetooth != null
    override val settingsTitleRes = R.string.taler_devices_manage

    override val icon: ImageVector
        @Composable get() = ImageVector.vectorResource(R.drawable.ic_taler_logo)

    override val logo: ImageVector
        @Composable get() = ImageVector.vectorResource(R.drawable.ic_taler_logo_full)

    override fun probe(): PaymentOptionState
    {
        usb?.refresh()
        return PaymentOptionState(
            id = id,
            enabled = true,
            status = PaymentOptionStatus.Ready,
            devices =
                listOfNotNull(nfcDevice(), bluetoothDevice()) +
                    usb
                        ?.state
                        ?.value
                        ?.takeIf { it.enabled }
                        ?.devices
                        .orEmpty()
                        .mapIndexed { index, device ->
                            PaymentDevice(
                                id = "usb:${device.id}",
                                name = context.getString(R.string.taler_usb_device, index + 1),
                                connected = device.status == TalerUsbStatus.Ready,
                                statusRes =
                                    when (device.status)
                                    {
                                        TalerUsbStatus.Ready -> null
                                        TalerUsbStatus.PermissionRequired -> R.string.taler_usb_permission_required
                                        TalerUsbStatus.Failed -> R.string.taler_usb_failed
                                    },
                            )
                        },
        )
    }

    override fun onLogout()
    {
        usb?.logout()
        bluetooth?.logout()
    }

    private fun bluetoothDevice(): PaymentDevice?
    {
        val state = bluetooth?.state?.value?.takeIf { it.enabled } ?: return null
        val selected = state.selected ?: return null
        return PaymentDevice(
            id = "ble:${selected.address}",
            name = selected.name,
            connected = state.status in setOf(TalerBleStatus.Ready, TalerBleStatus.Sending, TalerBleStatus.TooLong),
            statusRes = state.status.label(),
        )
    }

    @Composable
    override fun DetailContent(
        state: PaymentOptionState,
        actions: PaymentOptionActions,
    )
    {
        if (bluetooth != null && usb != null)
        {
            TalerDevicesContent(bluetooth, usb)
        }
    }

    private fun nfcDevice(): PaymentDevice?
    {
        // A tablet without NFC hardware has nothing to report; the QR code still works.
        val adapter = NfcAdapter.getDefaultAdapter(context) ?: return null
        val enabled = adapter.isEnabled
        return PaymentDevice(
            id = "nfc",
            nameRes = R.string.payment_device_nfc,
            connected = enabled,
            statusRes =
                if (enabled)
                {
                    R.string.payment_device_nfc_available
                }
                else
                {
                    R.string.payment_option_disabled
                },
        )
    }
}

/** Taking cash at the counter. Settled outside the app, so it only records the choice. */
object CashOption : PaymentOption
{
    override val id = "cash"
    override val nameRes = R.string.payment_option_cash
    override val descriptionRes = R.string.payment_option_cash_description

    override val icon: ImageVector
        @Composable get() = Icons.Default.Payments
}