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

import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.testing.*
import kotlinx.coroutines.runBlocking
import tech.libeufin.ebics.*
import tech.libeufin.ebics.test.*
import tech.libeufin.ebisync.*
import tech.libeufin.ebisync.db.*
import tech.libeufin.common.*
import tech.libeufin.common.test.*
import tech.libeufin.common.db.dbInit
import tech.libeufin.common.db.pgDataSource
import java.nio.file.NoSuchFileException
import kotlin.io.path.*
import java.nio.file.FileAlreadyExistsException
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import kotlin.random.Random
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull

/* ----- Setup ----- */

fun setup(
    conf: String = "test.conf",
    lambda: suspend (Database, EbisyncConfig) -> Unit
) = runBlocking {
    val cfg = ebisyncConfig(Path("conf/$conf"))
    pgDataSource(cfg.dbCfg.dbConnStr).run {
        dbInit(cfg.dbCfg, "libeufin-ebisync", true)
    }
    cfg.withDb(lambda)
}

@OptIn(kotlin.io.path.ExperimentalPathApi::class)
fun serverSetup(
    conf: String = "test.conf",
    lambda: suspend ApplicationTestBuilder.(Database, EbicsState) -> Unit
) = setup(conf) { db, cfg ->
    val bank = EbicsState()

    // Reset current keys
    val dir = Path("/tmp/ebics-test")
    dir.deleteRecursively()
    dir.createDirectories()

    // Set setup mock
    setMock(sequence {
        yield(bank::hev)
        yield(bank::ini)
        yield(bank::hia)
        yield(bank::hpb)
    })

    val client = httpClient()
    val ebicsLogger = EbicsLogger(null)
    
    val (clientKeys, bankKeys) = ebicsSetup(
        client,
        ebicsLogger,
        cfg,
        cfg,
        cfg.setup,
        false,
        false,
        true,
        true
    )
    val ebics = EbicsClient(
        cfg,
        client,
        db.ebics,
        ebicsLogger,
        clientKeys,
        bankKeys
    )

    testApplication {
        application {
            ebisyncApi((cfg.submit.source as Source.SyncAPI).auth, ebics, cfg.spa)
        }
        lambda(db, bank)
    }
}