/*
 * This file is part of LibEuFin.
 * Copyright (C) 2023, 2024, 2025, 2026 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/>
 */

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.testing.test
import tech.libeufin.common.crypto.CryptoUtil
import tech.libeufin.common.asUtf8
import tech.libeufin.nexus.*
import tech.libeufin.ebics.*
import tech.libeufin.nexus.cli.LibeufinNexus
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.io.path.*
import kotlin.test.Test
import kotlin.test.assertEquals

val nexusCmd = LibeufinNexus()

fun CliktCommand.testErr(cmd: String, msg: String) {
    val prevOut = System.err
    val tmpOut = ByteArrayOutputStream()
    System.setErr(PrintStream(tmpOut))
    val result = test(cmd)
    System.setErr(prevOut)
    val tmpStr = tmpOut.asUtf8()
    println(tmpStr)
    assertEquals(1, result.statusCode, "'$cmd' should have failed")
    val line = tmpStr.substringAfterLast(" - ").trimEnd('\n')
    println(line)
    assertEquals(msg, line)
}

class CliTest {

    /** Test server check */
    @Test
    fun serveCheck() {
        val confs = listOf(
            "mini" to 1,
            "test" to 0
        )
        for ((conf, statusCode) in confs) {
            val result = nexusCmd.test("serve --check -c conf/$conf.conf")
            assertEquals(statusCode, result.statusCode)
        }
    }

    /** Test list cmds */
    @Test
    fun listCheck() = setup { db, _ ->
        fun check() {
            for (list in listOf("incoming", "outgoing", "initiated", "initiated --awaiting-ack")) {
                val result = nexusCmd.test("list $list -c conf/test.conf")
                assertEquals(0, result.statusCode)
            }
        }
        // Check empty
        check()
        // Check with transactions
        registerIn(db)
        registerOut(db)
        check()
        // Check with taler transactions
        talerableOut(db)
        talerableIn(db)
        talerableCompletedIn(db)
        talerableKycIn(db)
        talerablePreparedIn(db)
        talerablePreparedCompletedIn(db)
        check()
        // Check with incomplete
        registerIncompleteIn(db)
        talerableIncompleteIn(db)
        registerIncompleteOut(db)
        talerablePreparedIncompleteIn(db)
        check()
    }
}