package world.respect.server

import io.ktor.server.config.*
import java.io.File

const val DEFAULT_DATA_DIR_NAME = "data"

const val SERVER_PROPERTIES_KEY_PORT = "port"

/**
 * KTOR server configuration that can be used to run a static directory on the same port.
 */
const val SERVER_CONFIG_KEY_STATICFILES = "ktor.extrastaticfiles.dir"

const val SERVER_CONFIG_KEY_DIRS_USE_VIRTUALHOST = "ktor.school.directories.virtualhost"

const val SERVER_CONFIG_KEY_REGISTRATION_PIN = "ktor.school.registration.pin"

/**
 * File that contains the password for directory management.
 */
const val DIRECTORY_ADMIN_FILENAME = "dir-admin.txt"

const val DEFAULT_DIR_ADMIN_PASS_LENGTH = 16

/**
 * Find the ktor server app source directory if/when the server is being run from source (e.g. via
 * gradlew command).
 *
 * When using the ./gradlew command or a gradle task in the IDE the working directory will be the
 * app-ktor-server module itself.
 *
 * When running as a Kotlin Program (e.g. clicking play next to main function), then the working
 * directory will be the project root directory.
 *
 */
fun ktorAppSourceDir(): File? {
    val userDirFile = File(System.getProperty("user.dir"))
    return when {
        //running in the respect-server directory
        userDirFile.name == "respect-server" && File(userDirFile, "build.gradle.kts").exists() -> userDirFile

        //running in the root source directory
        File(userDirFile, "settings.gradle.ktss").exists() &&
                File(userDirFile, "respect-server").exists() -> {
            File(userDirFile, "respect-server")
        }

        else -> null
    }
}

/*
 *  Find the ktor server app home directory.
 */
fun ktorAppHomeDir(): File {
    val appHomeProp = System.getProperty("app_home")
    val sourceDir: File? =  ktorAppSourceDir()

    return when {
        /*
         * If app home is explicitly set (which will be the case for the production version that
         * uses the binary script generated by Gradle application plugin) then accept this as the
         * app home dir
         */
        appHomeProp != null -> File(appHomeProp)

        /*
         * If app home is not explicitly set, and the current home directory is the root source
         * directory, then the app home directory is (current-working-directory)/respect-server .
         * This will be the case when running via the IDE (by clicking run/debug on ServerAppMain).
         */
        sourceDir != null -> sourceDir

        /*
         * Else use the current working directory
         */
        else -> File(System.getProperty("user.dir"))
    }
}

/**
 * The location of the server.properties file. When admin commands are run (e.g. addrealm etc)
 * the command line client needs to connect to the server over http. The admin command needs to have
 * authorization and needs to know the server port.
 *
 * This is secure because anyone who has access to the server.properties file would also have access
 * to the server directory itself.
 */
fun ktorServerPropertiesFile(
    dataDir: File
): File {
    return File(dataDir, "server.properties")
}

/**
 * Used when handling file properties. If the File is already absolute, leave it is as is. Otherwise,
 * return a File relative to the server home directory.
 */
fun File.relativeToHomeDirIfNotAbsolute() : File {
    return if(isAbsolute) {
        this
    }else {
        File(ktorAppHomeDir(), this.path)
    }
}

/**
 * Get a File for a property e.g. for the data directory or well known directory
 *
 * @param propertyName the config property name
 * @param defaultPath default value of property is null
 *
 * @return File object - if the path is absolute, returns the absolute File as is. If not, then will
 * return file relative to the server path as per ktorAppHomeDir()
 */
fun ApplicationConfig.fileProperty(
    propertyName: String, defaultPath: String
): File {
    val path = propertyOrNull(propertyName)?.getString() ?: defaultPath
    val file = File(path)

    return file.relativeToHomeDirIfNotAbsolute()
}

fun ApplicationConfig.filePropertyOrNull(
    propertyName: String
): File? {
    return propertyOrNull(propertyName)?.getString()?.let {
        File(it).relativeToHomeDirIfNotAbsolute()
    }
}


fun ApplicationConfig.absoluteDataDir() = fileProperty(
    propertyName = "ktor.respect.datadir", defaultPath = DEFAULT_DATA_DIR_NAME
)

fun ApplicationConfig.schoolDirsUseVirtualHost(): Boolean {
    return propertyOrNull(SERVER_CONFIG_KEY_DIRS_USE_VIRTUALHOST)?.getString()?.toBoolean() ?: false
}