package exh.uconfig

import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.asJsoup
import exh.EH_SOURCE_ID
import exh.EXH_SOURCE_ID
import exh.log.maybeInjectEHLogger
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import timber.log.Timber
import uy.kohesive.injekt.injectLazy

class EHConfigurator {
    private val prefs: PreferencesHelper by injectLazy()
    private val sources: SourceManager by injectLazy()

    private val configuratorClient = OkHttpClient.Builder()
            .maybeInjectEHLogger()
            .build()

    private fun EHentai.requestWithCreds(sp: Int = 1) = Request.Builder()
            .addHeader("Cookie", cookiesHeader(sp))

    private fun EHentai.execProfileActions(
        action: String,
        name: String,
        set: String,
        sp: Int
    ) =
        configuratorClient.newCall(requestWithCreds(sp)
                .url(uconfigUrl)
                .post(FormBody.Builder()
                        .add("profile_action", action)
                        .add("profile_name", name)
                        .add("profile_set", set)
                        .build())
                .build())
                .execute()

    private val EHentai.uconfigUrl get() = baseUrl + UCONFIG_URL

    fun configureAll() {
        val ehSource = sources.get(EH_SOURCE_ID) as EHentai
        val exhSource = sources.get(EXH_SOURCE_ID) as EHentai

        // Get hath perks
        val perksPage = configuratorClient.newCall(ehSource.requestWithCreds()
                .url(HATH_PERKS_URL)
                .build())
                .execute().asJsoup()

        val hathPerks = EHHathPerksResponse()

        perksPage.select(".stuffbox tr").forEach {
            val name = it.child(0).text().toLowerCase()
            val purchased = it.child(2).getElementsByTag("form").isEmpty()

            when (name) {
                // Thumbnail rows
                "more thumbs" -> hathPerks.moreThumbs = purchased
                "thumbs up" -> hathPerks.thumbsUp = purchased
                "all thumbs" -> hathPerks.allThumbs = purchased

                // Pagination sizing
                "paging enlargement i" -> hathPerks.pagingEnlargementI = purchased
                "paging enlargement ii" -> hathPerks.pagingEnlargementII = purchased
                "paging enlargement iii" -> hathPerks.pagingEnlargementIII = purchased
            }
        }

        Timber.d("Hath perks: $hathPerks")

        configure(ehSource, hathPerks)
        configure(exhSource, hathPerks)
    }

    fun configure(source: EHentai, hathPerks: EHHathPerksResponse) {
        // Delete old app profiles
        val scanReq = source.requestWithCreds().url(source.uconfigUrl).build()
        val resp = configuratorClient.newCall(scanReq).execute().asJsoup()
        var lastDoc = resp
        resp.select(PROFILE_SELECTOR).forEach {
            if (it.text() == PROFILE_NAME) {
                val id = it.attr("value")
                // Delete old profile
                lastDoc = source.execProfileActions("delete", "", id, id.toInt()).asJsoup()
            }
        }

        // Find available profile slot
        val availableProfiles = (1..3).toMutableList()
        lastDoc.select(PROFILE_SELECTOR).forEach {
            availableProfiles.remove(it.attr("value").toInt())
        }

        // No profile slots left :(
        if (availableProfiles.isEmpty())
            throw IllegalStateException("You are out of profile slots on ${source.name}, please delete a profile!")

        // Create profile in available slot
        val slot = availableProfiles.first()
        val response = source.execProfileActions("create",
                PROFILE_NAME,
                slot.toString(),
                1)

        // Build new profile
        val form = EhUConfigBuilder().build(hathPerks)

        // Send new profile to server
        configuratorClient.newCall(source.requestWithCreds(sp = slot)
                .url(source.uconfigUrl)
                .post(form)
                .build()).execute()

        // Persist slot + sk
        source.spPref().set(slot)

        val keyCookie = response.headers.toMultimap()["Set-Cookie"]?.find {
            it.startsWith("sk=")
        }?.removePrefix("sk=")?.substringBefore(';')
        val sessionCookie = response.headers.toMultimap()["Set-Cookie"]?.find {
            it.startsWith("s=")
        }?.removePrefix("s=")?.substringBefore(';')
        val hathPerksCookie = response.headers.toMultimap()["Set-Cookie"]?.find {
            it.startsWith("hath_perks=")
        }?.removePrefix("hath_perks=")?.substringBefore(';')

        if (keyCookie != null)
            prefs.eh_settingsKey().set(keyCookie)
        if (sessionCookie != null)
            prefs.eh_sessionCookie().set(sessionCookie)
        if (hathPerksCookie != null)
            prefs.eh_hathPerksCookies().set(hathPerksCookie)
    }

    companion object {
        private const val PROFILE_NAME = "TachiyomiEH App"
        private const val UCONFIG_URL = "/uconfig.php"
        // Always use E-H here as EXH does not have a perks page
        private const val HATH_PERKS_URL = "https://e-hentai.org/hathperks.php"
        private const val PROFILE_SELECTOR = "[name=profile_set] > option"
    }
}
