package com.lanyuanxiaoyao.digtal.market

import cn.hutool.core.date.DateUtil
import cn.hutool.crypto.SecureUtil
import com.lanyuanxiaoyao.squirrel.core.common.Management
import com.lanyuanxiaoyao.squirrel.core.common.PageParseException
import dev.failsafe.Failsafe
import dev.failsafe.FailsafeException
import dev.failsafe.RetryPolicy
import dev.failsafe.function.CheckedSupplier
import kotlin.time.Duration.Companion.seconds
import kotlin.time.toJavaDuration
import kotlinx.coroutines.runBlocking
import org.jsoup.Jsoup
import org.slf4j.LoggerFactory

data class ArticleLink(
    val code: String,
    val url: String,
    val hash: String,
    val title: String?,
    val datetime: String?,
)

private val logger = LoggerFactory.getLogger("Helper")

private val retryPolicy = RetryPolicy
    .builder<Any>()
    .withDelay(10.seconds.toJavaDuration())
    .withMaxRetries(2)
    .handleIf { e -> (e is PageParseException).not() }
    .build()

@Suppress("UNCHECKED_CAST")
fun parseArticleLink(management: Management, code: String, url: String?, recursive: Boolean = false): List<ArticleLink> {
    var next: String? = url
    val links = mutableListOf<ArticleLink>()
    do {
        val page = try {
            Failsafe
                .with(retryPolicy)
                .get(CheckedSupplier {
                    runBlocking { management.parse(code, next!!) }
                })
        } catch (e: FailsafeException) {
            logger.error("解析失败：${next}", e)
            continue
        }
        (page["list"] as? List<Map<String, Any>>)
            ?.let { list ->
                for (item in list) {
                    val link = item["link"] as String?
                    if (link.isNullOrBlank()) {
                        logger.warn("链接为空：{} {}", item["title"] as String?, next)
                    } else {
                        links.add(
                            ArticleLink(
                                code,
                                link,
                                SecureUtil.md5(link),
                                item["title"] as String?,
                                item["datetime"] as String?,
                            )
                        )
                    }
                }
            }
        next = page["next"] as String?
    } while (recursive && !next.isNullOrBlank())
    return links
}

fun parseArticle(management: Management, articleLink: ArticleLink): Article? {
    val (code, url, hash, title, datetime) = articleLink
    return parseArticle(management, code, url, hash, title, datetime)
}

fun parseArticle(management: Management, code: String, url: String, hash: String, title: String?, datetime: String?): Article? {
    logger.info("标题：{} 时间：{}", title, datetime)
    val page = try {
        Failsafe
            .with(retryPolicy)
            .get(CheckedSupplier {
                runBlocking { management.parse(code, url) }
            })
    } catch (e: FailsafeException) {
        logger.error("解析失败：${url}", e)
        return null
    }
    (page["text"] as? Map<*, *>)?.let { text ->
        var datetimeText = text["datetime"] as? String
        val createTime = try {
            if (datetimeText.isNullOrBlank()) {
                datetimeText = datetime
            }
            if (datetimeText?.matches(Regex("\\d{13}")) == true) {
                DateUtil
                    .date(datetimeText.toLong())
                    .toTimestamp()
            } else if (datetimeText?.matches(Regex("\\d{10}")) == true) {
                DateUtil
                    .date(datetimeText.toLong() * 1000)
                    .toTimestamp()
            } else {
                DateUtil
                    .parse(
                        datetimeText,
                        "yyyy-MM-dd HH:mm:ss",
                        "yyyy-MM-dd",
                        "yyyy年MM月dd日 HH:mm",
                        "yyyy-MM-dd HH:mm",
                    )
                    .toTimestamp()
            }
        } catch (e: Exception) {
            logger.error("解析 $datetimeText 失败", e)
            null
        }
        val sourceText = (text["source"] as? String) ?: ""
        val source = if (sourceText.isBlank()) {
            sourceText
        } else {
            sourceText.let {
                val document = Jsoup.parse((it as String))
                document
                    .select("script")
                    .forEach { it.remove() }
                document
                    .select("link")
                    .forEach { it.remove() }
                document.forEachNode { node -> node.removeAttr("style") }
                document
                    .body()
                    .html()
            }
        }
        return Article(
            id = hash,
            code = code,
            url = url,
            title = null,
            author = null,
            category = null,
            text = text["content"] as String? ?: "",
            html = source,
            subtitle = null,
            description = null,
            tags = null,
            createTime = createTime,
            pushed = false,
            error = null,
        )
    } ?: return null
}