package bou.amine.apps.readerforselfossv2.model

import bou.amine.apps.readerforselfossv2.utils.DateUtils
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*

class SelfossModel {

    @Serializable
    data class Tag(
        val tag: String,
        val color: String,
        val unread: Int
    )

    @Serializable
    class Stats(
        val total: Int,
        val unread: Int,
        val starred: Int
    )

    @Serializable
    data class Spout(
        val name: String,
        val description: String
    )

    @Serializable
    data class ApiVersion(
        val version: String?,
        val apiversion: String?
    ) {
        fun getApiMajorVersion() : Int {
            var versionNumber = 0
            if (apiversion != null) {
                versionNumber = apiversion.substringBefore(".").toInt()
            }
            return versionNumber
        }
    }

    @Serializable
    data class Source(
        val id: Int,
        val title: String,
        @Serializable(with = TagsListSerializer::class)
        val tags: List<String>,
        val spout: String,
        val error: String,
        val icon: String?
    )

    @Serializable
    data class Item(
        val id: Int,
        val datetime: String,
        val title: String,
        val content: String,
        @Serializable(with = BooleanSerializer::class)
        var unread: Boolean,
        @Serializable(with = BooleanSerializer::class)
        var starred: Boolean,
        val thumbnail: String?,
        val icon: String?,
        val link: String,
        val sourcetitle: String,
        @Serializable(with = TagsListSerializer::class)
        val tags: List<String>
    ) {
        // TODO: maybe find a better way to handle these kind of urls
        fun getLinkDecoded(): String {
            var stringUrl: String
            stringUrl =
                if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
                    if (link.contains("&amp;url=")) {
                        link.substringAfter("&amp;url=")
                    } else {
                        this.link.replace("&amp;", "&")
                    }
                } else {
                    this.link.replace("&amp;", "&")
                }

            // handle :443 => https
            if (stringUrl.contains(":443")) {
                stringUrl = stringUrl.replace(":443", "").replace("http://", "https://")
            }

            // handle url not starting with http
            if (stringUrl.startsWith("//")) {
                stringUrl = "http:$stringUrl"
            }

            return stringUrl
        }

        fun sourceAndDateText(): String =
            this.sourcetitle.getHtmlDecoded() + DateUtils.parseRelativeDate(this.datetime)

        fun toggleStar(): Item {
            this.starred = !this.starred
            return this
        }
    }

    // TODO: this seems to be super slow.
    object TagsListSerializer : KSerializer<List<String>> {
        override fun deserialize(decoder: Decoder): List<String> {
            return when(val json = ((decoder as JsonDecoder).decodeJsonElement())) {
                is JsonArray -> json.toList().map { it.toString() }
                else -> json.toString().split(",")
            }

        }

        override val descriptor: SerialDescriptor
            get() = PrimitiveSerialDescriptor("tags", PrimitiveKind.STRING)

        override fun serialize(encoder: Encoder, value: List<String>) {
            TODO("Not yet implemented")
        }
    }

    object BooleanSerializer : KSerializer<Boolean> {
        override fun deserialize(decoder: Decoder): Boolean {
            val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
            return if (json.booleanOrNull != null) {
                json.boolean
            } else {
                json.int == 1
            }
        }

        override val descriptor: SerialDescriptor
            get() = PrimitiveSerialDescriptor("b", PrimitiveKind.BOOLEAN)

        override fun serialize(encoder: Encoder, value: Boolean) {
            TODO("Not yet implemented")
        }
    }
}
