package com.syncflow

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.syncflow.data.providers.sftp.SftpProvider
import com.syncflow.data.security.CredentialStore
import com.syncflow.domain.model.CloudAccount
import com.syncflow.domain.model.ProviderType
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assume.assumeTrue
import org.junit.Test
import org.junit.runner.RunWith
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream

/**
 * Live SFTP test (the other major provider code path: sshj). Runs against a throwaway SFTP
 * server. Skips unless -e sftpHost/sftpPort/sftpUser/sftpPass are provided.
 */
@RunWith(AndroidJUnit4::class)
class SftpProviderTest {

    private val ctx = InstrumentationRegistry.getInstrumentation().targetContext
    private val args = InstrumentationRegistry.getArguments()

    private fun provider() = SftpProvider(
        CloudAccount(
            id = 1, displayName = "sftp", email = null, providerType = ProviderType.SFTP,
            credentialJson = """{"username":"${args.getString("sftpUser")}","password":"${args.getString("sftpPass")}"}""",
            serverUrl = args.getString("sftpHost"), port = args.getString("sftpPort")?.toInt(),
        ),
        CredentialStore(ctx),
    )

    @Test fun sftpFullRoundTrip() = runBlocking {
        assumeTrue("sftp* args required", args.getString("sftpHost") != null)
        val p = provider()
        val dir = "upload/it_${System.currentTimeMillis()}"

        // Skip (don't fail) if the endpoint isn't reachable from the test runner's network —
        // e.g. a phone on an isolated VLAN that only reaches services via the reverse proxy.
        assumeTrue("SFTP endpoint not reachable from this device's network", p.testConnection().isSuccess)
        assertTrue("mkdir", p.createDirectory(dir).isSuccess)

        // upload (atomic temp + rename), list, download
        val body = "sftp round-trip ✓".toByteArray()
        assertTrue("upload", p.uploadFile(ByteArrayInputStream(body), "$dir/f.txt", body.size.toLong()).isSuccess)
        assertTrue("f.txt" in p.listFiles(dir).getOrThrow().map { it.name })
        val out = ByteArrayOutputStream(); p.downloadFile("$dir/f.txt", out).getOrThrow()
        assertEquals("sftp round-trip ✓", out.toString("UTF-8"))

        // atomic overwrite (temp + rename over existing)
        val v2 = "updated-content".toByteArray()
        assertTrue(p.uploadFile(ByteArrayInputStream(v2), "$dir/f.txt", v2.size.toLong()).isSuccess)
        val out2 = ByteArrayOutputStream(); p.downloadFile("$dir/f.txt", out2).getOrThrow()
        assertEquals("updated-content", out2.toString("UTF-8"))

        // special / non-ASCII name (SFTP handles UTF-8 natively, no URL encoding)
        val special = "café & rapport (1).txt"
        assertTrue(p.uploadFile(ByteArrayInputStream("x".toByteArray()), "$dir/$special", 1).isSuccess)
        assertTrue(special in p.listFiles(dir).getOrThrow().map { it.name })

        // delete
        assertTrue(p.deleteFile("$dir/f.txt").isSuccess)
        assertTrue("f.txt" !in p.listFiles(dir).getOrThrow().map { it.name })
    }
}
