package de.sebse.fuplanner2.utils

import java.util.*
import kotlin.math.ceil
import kotlin.random.Random


fun getFaker(): Faker {
    return Faker(42)
}

class Faker(randomSeed: Int) {
    private val random = Random(randomSeed)

    val name: FakerName
        get() = FakerName(random)

    val internet: FakerInternet
        get() = FakerInternet(random)

    val primitive: FakerPrimitive
        get() = FakerPrimitive(random)

    val other: FakerOther
        get() = FakerOther(random)

    val strings: FakerStrings
        get() = FakerStrings(random)
}

class FakerName(private val random: Random) {
    fun lastName(): String {
        return LASTNAMES.random(random)
    }

    fun firstName(): String {
        return FIRSTNAMES.random(random)
    }

    companion object {
        private val LASTNAMES = listOf("Müller", "Schmidt", "Schneider", "Fischer", "Weber",
            "Meyer", "Wagner", "Becker", "Schulz", "Hoffmann", "Schäfer", "Koch", "Bauer",
            "Richter", "Klein", "Schröder", "Wolf", "Neumann", "Schwarz", "Zimmermann", "Braun",
            "Hofmann", "Hartmann", "Schmitt", "Krüger", "Schmitz", "Lange", "Werner", "Krause",
            "Meier")
        private val FIRSTNAMES = listOf("Daisie", "Elisabeth", "Dyane", "Valry", "Terrye",
            "Susette", "Karen", "Cecile", "Hesther", "Faunie", "Cissy", "Babb", "Cristionna",
            "Paola", "Claribel", "Eveline", "June", "Ange", "Ebba", "Willow", "Aggi",
            "Anne-Corinne", "Merl", "Di", "Kit", "Dreddy", "Fayette", "Griselda", "Emmey",
            "Timothea", "Lucia", "Jacky", "Aline", "Rikki", "Sandye", "Aura", "Cordula", "Linell",
            "Adeline", "Jessalyn", "Mariya", "Ema", "Hermine", "Annalee", "Agatha", "Wrennie",
            "Florinda", "Malynda", "Bess", "Binni")
    }
}

class FakerInternet(private val random: Random) {
    fun email(name: String?): String {
        val salt = name ?: FakerName(random).let {
            "${it.firstName()} ${it.lastName()}"
        }
        val user = salt
            .lowercase()
            .replace(Regex("[ -]"), ".")
            .replace(Regex("[^a-z0-9.]"), "")
        return "$user@fu-berlin.de"
    }

    fun mime(): String {
        return MIME_TYPES.random(random)
    }

    fun url(): String {
        return "https://example.de/file"
    }

    companion object {
        private val MIME_TYPES = listOf("application/pdf", "text/plain", "text/csv",
            "application/msword")
    }
}

class FakerPrimitive(private val random: Random) {
    fun int(min: Int, max: Int): Int {
        return (min..max).random(random)
    }

    fun long(min: Long, max: Long): Long {
        return (min..max).random(random)
    }

    fun bool(trueProbability: Float): Boolean {
        return random.nextFloat() < trueProbability
    }
}

class FakerOther(private val random: Random) {
    fun lastRefreshed(): Long {
        return FakerPrimitive(random).long(
            System.currentTimeMillis() - DIFF,
            System.currentTimeMillis() + DIFF
        )
    }
    fun date(startDay: Int, endDay: Int): Long {
        return FakerPrimitive(random).long(
            System.currentTimeMillis() + DAY * startDay,
            System.currentTimeMillis() + DAY * endDay
        )
    }

    companion object {
        const val DAY = 1000L*60*60*24
        const val DIFF = DAY*5
    }
}

class FakerStrings(private val random: Random) {
    fun lorem(min: Int, max: Int): String {
        val length = (min..max).random(random)
        val loremArray = LOREM.split(" ").size
        val n = ceil(length.toFloat() / loremArray).toInt() + 1
        val repeatedArray = ("$LOREM ")
            .repeat(n)
            .trim()
            .split(" ")
        return repeatedArray.run {
            if (size-length < 1) throw Error("$n + $size<$length")
            val from = (0 until size-length).random()
            subList(from, from+length)
        }.joinToString(" ")
    }

    fun title(): String {
        return lorem(3, 7)
            .split(" ")
            .joinToString(" ") { word ->
                word.replaceFirstChar { it.uppercase() }
            }
    }

    fun uuid(namespace: String): String {
        return UUID.nameUUIDFromBytes(namespace.encodeToByteArray()).toString();
    }

    fun courseTypes(): String {
        return COURSE_TYPES.random(random)
    }
    
    companion object {
        const val LOREM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy "+
                "eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam "+
                "voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita "+
                "kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem "+
                "ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor "+
                "invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos "+
                "et accusam et justo duo dolores et ea rebum."

        val COURSE_TYPES = listOf("Vorlesung + Übung", "Vorlesung + Seminar am PC", "Praktikum",
            "Vorlesung/Übung")
    }
}
