/*
 * This file is part of LibEuFin.
 * Copyright (C) 2024-2025 Taler Systems S.A.

 * LibEuFin is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3, or
 * (at your option) any later version.

 * LibEuFin 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 Affero General
 * Public License for more details.

 * You should have received a copy of the GNU Affero General Public
 * License along with LibEuFin; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>
 */

package tech.libeufin.bank.cli

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.parameters.arguments.*
import com.github.ajalt.clikt.parameters.groups.provideDelegate
import com.github.ajalt.clikt.parameters.options.*
import tech.libeufin.bank.bankConfig
import tech.libeufin.bank.db.AccountDAO.AccountPatchAuthResult
import tech.libeufin.bank.logger
import tech.libeufin.bank.withDb
import tech.libeufin.common.TalerCmd
import tech.libeufin.common.crypto.checkPw
import com.github.ajalt.mordant.terminal.*

class ChangePw : TalerCmd("passwd") {
    override fun help(context: Context) = "Change account password"

    private val username by argument("username", help = "Account username")
    private val password by argument(
        "password", 
        help = "Account password used for authentication"
    ).defaultLazy("prompt") {
        val terminal = Terminal()
        ConfirmationPrompt.create(
            "Password",
            "Repeat for confirmation",
            "Values do not match, try again",
            {
                object : Prompt<String>(
                    prompt = it,
                    terminal = terminal,
                    hideInput = true
                ) {
                    override fun convert(input: String): ConversionResult<String> {
                        return ConversionResult.Valid(input)
                    }
                }
            }
        ).ask()!!
    }
    override fun run() = cliCmd(logger) {
        bankConfig(config).withDb { db, cfg ->
            val password = password.checkPw(cfg.pwdCheckQuality)
            val res = db.account.reconfigPassword(username, password, null, true, cfg.pwCrypto)
            when (res) {
                AccountPatchAuthResult.UnknownAccount ->
                    throw Exception("Password change for '$username' account failed: unknown account")
                AccountPatchAuthResult.OldPasswordMismatch,
                    AccountPatchAuthResult.TanRequired -> { /* Can never happen */ }
                AccountPatchAuthResult.Success ->
                    logger.info("Password change for '$username' account succeeded")
            }
        }
    }
}