from datetime import datetime
from re import findall, sub

from lxml import etree

from .assert_funcs import AssertArticleStatusNormal, AssertArticleUrl
from .basic_apis import (GetArticleCommentsJsonDataApi,
                         GetArticleHtmlJsonDataApi, GetArticleJsonDataApi)
from .headers import PC_header, jianshu_request_header


def GetArticleTitle(article_url: str) -> str:
    """获取文章标题

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 文章标题
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["public_title"]
    return result

def GetArticleAuthorName(article_url: str) -> str:
    """获取文章作者名

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 文章作者名
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleHtmlJsonDataApi(article_url)
    result = json_obj["props"]["initialState"]["note"]["data"]["user"]["nickname"]
    return result

def GetArticleReadsCount(article_url: str) -> str:
    """获取文章阅读量

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 文章阅读量
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleHtmlJsonDataApi(article_url)
    result = json_obj["props"]["initialState"]["note"]["data"]["views_count"]
    return result

def GetArticleWordage(article_url: str) -> str:
    """获取文章总字数

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 文章总字数
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleHtmlJsonDataApi(article_url)
    result = json_obj["props"]["initialState"]["note"]["data"]["wordage"]
    return result

def GetArticleLikesCount(article_url: str) -> int:
    """获取文章点赞量

    Args:
        article_url (str): 文章 Url

    Returns:
        int: 文章点赞量
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["likes_count"]
    return result

def GetArticleCommentsCount(article_url: str) -> int:
    """获取文章评论量

    Args:
        article_url (str): 文章 Url

    Returns:
        int: 文章评论量
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["public_comment_count"]
    return result

def GetArticleMostValuableCommentsCount(article_url: str) -> int:
    """获取文章精选评论量

    Args:
        article_url (str): 文章 Url

    Returns:
        int: 文章精选评论量
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["featured_comments_count"]
    return result

def GetArticleTotalFPCount(article_url: str) -> int:
    """获取文章总获钻量

    Args:
        article_url (str): 文章 Url

    Returns:
        int: 文章总获钻量
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["total_fp_amount"] / 1000
    return result

def GetArticleDescription(article_url: str) -> str:
    """获取文章摘要

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 文章摘要
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["description"]
    return result

def GetArticlePublishTime(article_url: str) -> datetime:
    """获取文章发布时间

    Args:
        article_url (str): 文章 Url

    Returns:
        datetime: 文章发布时间
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = datetime.fromisoformat(json_obj["first_shared_at"])
    return result

def GetArticleUpdateTime(article_url: str) -> datetime:
    """获取文章更新时间

    Args:
        article_url (str): 文章 Url

    Returns:
        datetime: 文章更新时间
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = datetime.fromtimestamp(json_obj["last_updated_at"])
    return result

def GetArticlePaidStatus(article_url: str) -> bool:
    """获取文章付费状态

    Args:
        article_url (str): 文章 Url

    Returns:
        bool: 文章付费状态，True 为付费文章，False 为免费文章
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    paid_type = {
        "free": False, 
        "fbook_free": False, 
        "pbook_free":False, 
        "paid": True, 
        "fbook_paid": True, 
        "pbook_paid":True
    }
    result = paid_type[json_obj["paid_type"]]
    return result

def GetArticleReprintStatus(article_url: str) -> bool:
    """获取文章转载声明状态

    Args:
        article_url (str): 文章 Url

    Returns:
        bool: 文章转载声明状态，True 为允许转载，False 为禁止转载
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["reprintable"]
    return result

def GetArticleCommentStatus(article_url: str) -> bool:
    """获取文章评论状态

    Args:
        article_url (str): 文章 Url

    Returns:
        bool: 文章评论状态，True 为开启评论，False 为关闭评论
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    result = json_obj["commentable"]
    return result


def GetArticleHtml(article_url: str) -> str:
    """获取 Html 格式的文章内容

    # ! 该函数可以获取设置禁止转载的文章内容，请尊重作者版权，由此带来的风险由您自行承担
    # ! 该函数不能获取需要付费的文章内容
    # ! 文章中的图片描述将会丢失

    Args:
        article_url (str): 文章 Url

    Returns:
        str: Html 格式的文章内容
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    html_text = json_obj["free_content"]
    html_text = sub(r'<div class="image-[\w]*" [ \w+-="]*>', "", html_text)  # 去除 image-view 和 image-container
    html_text = sub(r'<div class="image-package">', "", html_text)  # 去除 image-package
    html_text = sub(r'<div class="image-container-fill".+>', "", html_text)  # 去除 image-container-fill
    old_img_blocks = findall(r'\<img[ \w+-="]*>', html_text)  # 匹配旧的 img 标签
    img_names = findall(r"\w+-\w+.[jpg | png]{3}",html_text)  # 获取图片名称
    new_img_blocks = ["".join(['<img src="https://upload-images.jianshu.io/upload_images/', \
                    img_name, '">']) for img_name in img_names]  # 拼接新的 img 标签
    if len(old_img_blocks) == 0:
        replaced = html_text
    for index in range(len(old_img_blocks)):
        if index == 0:
            replaced = html_text.replace(old_img_blocks[index], new_img_blocks[index])
        else:
            replaced = replaced.replace(old_img_blocks[index], new_img_blocks[index])  # 替换 img 标签
    return replaced

def GetArticleText(article_url: str) -> str:
    """获取纯文本格式的文章内容

    # ! 该函数可以获取设置禁止转载的文章内容，请尊重作者版权，由此带来的风险由您自行承担
    # ! 该函数不能获取需要付费的文章内容

    Args:
        article_url (str): 文章 Url

    Returns:
        str: 纯文本格式的文章内容
    """
    AssertArticleUrl(article_url)
    AssertArticleStatusNormal(article_url)
    json_obj = GetArticleJsonDataApi(article_url)
    html_text = json_obj["free_content"]
    html_obj = etree.HTML(html_text)
    result = "".join(html_obj.itertext())
    result = sub(r"\s{2,}", "", result)
    return result

def GetArticleCommentsData(article_id: int, page: int = 1, count: int = 10, 
                           author_only: bool = False, sorting_method: str = "positive") -> list:
    """获取文章评论信息

    Args:
        article_id (int): 文章 Id
        page (int, optional): 页码. Defaults to 1.
        count (int, optional): 每次获取的评论数（不包含子评论）. Defaults to 10.
        author_only (bool, optional): 为 True 时只获取作者发布的评论，包含作者发布的子评论及其父评论. Defaults to False.
        sorting_method (str, optional): 排序方式，为”positive“时按时间正序排列，为”reverse“时按时间倒序排列. Defaults to "positive".

    Returns:
        list: 评论信息
    """
    order_by = {
        "positive": "asc", 
        "reverse": "desc"
    }[sorting_method]
    json_obj = GetArticleCommentsJsonDataApi(article_id, page, count, author_only, order_by)
    result = []
    for item in json_obj["comments"]:
        item_data = {
            "cmid": item["id"], 
            "publish_time": datetime.fromisoformat(item["created_at"]), 
            "content": item["compiled_content"], 
            "floor": item["floor"], 
            "images": [image["url"] for image in item["images"]], 
            "likes_count": item["likes_count"], 
            "sub_comments_count": item["children_count"], 
            "user": {
                "uid": item["user"]["id"], 
                "name": item["user"]["nickname"], 
                "uslug": item["user"]["slug"], 
                "avatar_url": item["user"]["avatar"]
            }
        }
        try:
            item["member"]
        except KeyError:  # 没有开通会员
            pass
        else:
            item_data["user"]["vip_type"] = {
                    "bronze": "铜牌", 
                    "silver": "银牌", 
                    "gold": "黄金", 
                    "platina": "白金"
            }[item["user"]["member"]["type"]]
            item_data["user"]["vip_expire_date"] = datetime.fromtimestamp(item["user"]["member"]["expires_at"])
        
        try:
            item["children"]
        except KeyError:  # 没有子评论
            pass
        else:
            item_data["sub_comments"] = []
            for sub_comment in item["children"]:
                sub_comment_data = {
                "cmid": sub_comment["id"], 
                "publish_time": datetime.fromisoformat(sub_comment["created_at"]), 
                "content": sub_comment["compiled_content"], 
                "images": [image["url"] for image in sub_comment["images"]], 
                "parent_comment_id": sub_comment["parent_id"], 
                "user": {
                    "uid": sub_comment["user"]["id"], 
                    "name": sub_comment["user"]["nickname"], 
                    "uslug": sub_comment["user"]["slug"], 
                    "avatar_url": sub_comment["user"]["avatar"]
                }
            }
                
                try:
                    sub_comment["user"]["member"]
                except KeyError:  # 没有开通会员
                    pass
                else:
                    sub_comment_data["user"]["vip_type"] = {
                            "bronze": "铜牌",
                            "silver": "银牌" , 
                            "gold": "黄金", 
                            "platina": "白金"
                    }[item["user"]["member"]["type"]]
                    sub_comment_data["user"]["vip_expire_date"] = datetime.fromtimestamp(sub_comment["user"]["member"]["expires_at"])

                item_data["sub_comments"].append(sub_comment_data)
                    
        result.append(item_data)
    return result