import com.xenomachina.argparser.ArgParser
import com.xenomachina.argparser.default
import com.xenomachina.argparser.mainBody
import org.fusesource.jansi.internal.CLibrary.STDIN_FILENO
import org.fusesource.jansi.internal.CLibrary.isatty
import java.nio.charset.Charset
import java.security.MessageDigest
import kotlin.system.exitProcess

class Args(parser: ArgParser) {
    val encrypt by parser.flagging("-e", "--encrypt", help = "Encrypt stdin instead of decrypting")

    val keyExchange by parser
        .storing("-k", "--key-exchange", help = "Key-Exchange header value, required if nonce is not provided")
        .default<String?>(null)

    val cloudPassword by parser
        .storing("-p", "--password", help = "Cloud password, if camera has been provisioned")
        .default<String?>(null)

    val username by parser
        .storing("-u", "--username", help = "User name, either admin or none. Default admin")
        .default<String>("admin")

    val nonce by parser
        .storing("-n", "--nonce", help = "Nonce, required if key-exchange is not provided")
        .default<String?>(null)
}

fun main(args: Array<String>) = mainBody {
    ArgParser(args).parseInto(::Args).run {
        if (keyExchange == null && nonce == null) {
            System.err.println("Either the Key-Exchange or the nonce must be provided!")
            exitProcess(1)
        }
        if (cloudPassword == null) {
            System.err.println("Cloud password not provided, using the default one for unprovisioned cameras")
        }
        if (isatty(STDIN_FILENO) == 1) {
            System.err.println("Data to ${if (encrypt) "encrypt" else "decrypt"} must be sent to standard input!")
            exitProcess(1)
        }
        val toProcess = System.`in`.readAllBytesCompat()
        if (toProcess == null) {
            System.err.println("Unable to read data from stdin!")
            exitProcess(1)
        }

        val hashedPassword: String? = cloudPassword?.let {
            MessageDigest
                .getInstance("MD5")
                .apply { update(it.toByteArray(Charset.forName("UTF-8"))) }
                .digest()
                .toHexString()
        }

        val aes = if (keyExchange != null) {
            StreamAesUtils.generateFromExchangeKeyAndSuperSecretKey(keyExchange, hashedPassword)
        } else {
            StreamAesUtils.fromUserNonceSuperSecretKey(username, nonce, hashedPassword)
        }

        val output = if (encrypt) {
            aes.encrypt(toProcess)
        } else {
            aes.decrypt(toProcess)
        }

        System.out.write(output)
    }
}