import json
from django.utils.html import strip_tags
from django.template.defaultfilters import truncatewords
from djangoblog.plugin_manage.base_plugin import BasePlugin
from djangoblog.plugin_manage import hooks
from blog.models import Article, Category, Tag
from djangoblog.utils import get_blog_setting


class SeoOptimizerPlugin(BasePlugin):
    """
    SEO 优化插件
    功能：为网站提供全面的SEO优化支持，包括meta标签和JSON-LD结构化数据
    提升网站在搜索引擎中的可见性和排名
    """

    # 插件基本信息
    PLUGIN_NAME = 'SEO 优化器'
    PLUGIN_DESCRIPTION = '为文章、页面等提供 SEO 优化，动态生成 meta 标签和 JSON-LD 结构化数据。'
    PLUGIN_VERSION = '0.2.0'
    PLUGIN_AUTHOR = 'liuangliangyy'  # 注意：这里可能有拼写错误，应该是 liangliangyy

    def register_hooks(self):
        """
        注册钩子函数
        将SEO生成方法注册到head_meta钩子，在页面头部生成SEO相关标签
        """
        hooks.register('head_meta', self.dispatch_seo_generation)

    def _get_article_seo_data(self, context, request, blog_setting):
        """
        生成文章页面的SEO数据

        参数:
            context: 模板上下文，包含文章等信息
            request: HTTP请求对象
            blog_setting: 博客设置

        返回值:
            dict - 包含文章页面SEO数据的字典
        """
        # 从上下文中获取文章对象
        article = context.get('article')
        # 确保是Article实例且存在
        if not isinstance(article, Article):
            return None

        # 生成描述：移除HTML标签并截取前150个字符
        description = strip_tags(article.body)[:150]
        # 生成关键词：使用文章标签，如果没有则使用站点默认关键词
        keywords = ",".join([tag.name for tag in article.tags.all()]) or blog_setting.site_keywords

        # 生成Open Graph meta标签（用于社交媒体分享）
        meta_tags = f'''
        <meta property="og:type" content="article"/>
        <meta property="og:title" content="{article.title}"/>
        <meta property="og:description" content="{description}"/>
        <meta property="og:url" content="{request.build_absolute_uri()}"/>
        <meta property="article:published_time" content="{article.pub_time.isoformat()}"/>
        <meta property="article:modified_time" content="{article.last_modify_time.isoformat()}"/>
        <meta property="article:author" content="{article.author.username}"/>
        <meta property="article:section" content="{article.category.name}"/>
        '''
        # 为每个标签添加article:tag meta标签
        for tag in article.tags.all():
            meta_tags += f'<meta property="article:tag" content="{tag.name}"/>'
        # 添加网站名称
        meta_tags += f'<meta property="og:site_name" content="{blog_setting.site_name}"/>'

        # 生成JSON-LD结构化数据（用于搜索引擎理解内容结构）
        structured_data = {
            "@context": "https://schema.org",
            "@type": "Article",  # 文章类型
            "mainEntityOfPage": {"@type": "WebPage", "@id": request.build_absolute_uri()},
            "headline": article.title,  # 文章标题
            "description": description,  # 文章描述
            "image": request.build_absolute_uri(article.get_first_image_url()),  # 文章首图
            "datePublished": article.pub_time.isoformat(),  # 发布时间
            "dateModified": article.last_modify_time.isoformat(),  # 修改时间
            "author": {"@type": "Person", "name": article.author.username},  # 作者信息
            "publisher": {"@type": "Organization", "name": blog_setting.site_name}  # 发布者信息
        }
        # 如果没有图片，移除image字段
        if not structured_data.get("image"):
            del structured_data["image"]

        return {
            "title": f"{article.title} | {blog_setting.site_name}",  # 页面标题
            "description": description,  # 页面描述
            "keywords": keywords,  # 页面关键词
            "meta_tags": meta_tags,  # meta标签
            "json_ld": structured_data  # JSON-LD数据
        }

    def _get_category_seo_data(self, context, request, blog_setting):
        """
        生成分类页面的SEO数据

        参数:
            context: 模板上下文
            request: HTTP请求对象
            blog_setting: 博客设置

        返回值:
            dict - 包含分类页面SEO数据的字典
        """
        # 从上下文中获取分类名称
        category_name = context.get('tag_name')  # 注意：这里变量名可能有误，应该是category_name
        if not category_name:
            return None

        # 获取分类对象
        category = Category.objects.filter(name=category_name).first()
        if not category:
            return None

        # 生成页面基本信息
        title = f"{category.name} | {blog_setting.site_name}"
        description = strip_tags(category.name) or blog_setting.site_description
        keywords = category.name

        # 生成面包屑导航的结构化数据
        breadcrumb_items = [
            {"@type": "ListItem", "position": 1, "name": "首页", "item": request.build_absolute_uri('/')}
        ]
        breadcrumb_items.append(
            {"@type": "ListItem", "position": 2, "name": category.name, "item": request.build_absolute_uri()})

        # 面包屑导航的JSON-LD数据
        structured_data = {
            "@context": "https://schema.org",
            "@type": "BreadcrumbList",
            "itemListElement": breadcrumb_items
        }

        return {
            "title": title,
            "description": description,
            "keywords": keywords,
            "meta_tags": "",
            "json_ld": structured_data
        }

    def _get_default_seo_data(self, context, request, blog_setting):
        """
        生成默认页面（首页等）的SEO数据

        参数:
            context: 模板上下文
            request: HTTP请求对象
            blog_setting: 博客设置

        返回值:
            dict - 包含默认页面SEO数据的字典
        """
        # 网站类型的JSON-LD结构化数据
        structured_data = {
            "@context": "https://schema.org",
            "@type": "WebSite",
            "url": request.build_absolute_uri('/'),
            "potentialAction": {
                "@type": "SearchAction",
                "target": f"{request.build_absolute_uri('/search/')}?q={{search_term_string}}",
                "query-input": "required name=search_term_string"
            }
        }
        return {
            "title": f"{blog_setting.site_name} | {blog_setting.site_description}",
            "description": blog_setting.site_description,
            "keywords": blog_setting.site_keywords,
            "meta_tags": "",
            "json_ld": structured_data
        }

    def dispatch_seo_generation(self, metas, context):
        """
        SEO数据分发器 - 根据当前页面类型调用相应的SEO生成方法

        参数:
            metas: 原始的meta标签内容
            context: 模板上下文

        返回值:
            str - 完整的SEO相关HTML代码
        """
        request = context.get('request')
        if not request:
            return metas

        # 获取当前视图名称，用于判断页面类型
        view_name = request.resolver_match.view_name
        blog_setting = get_blog_setting()

        seo_data = None
        # 根据视图名称调用不同的SEO生成方法
        if view_name == 'blog:detailbyid':
            seo_data = self._get_article_seo_data(context, request, blog_setting)
        elif view_name == 'blog:category_detail':
            seo_data = self._get_category_seo_data(context, request, blog_setting)

        # 如果没有匹配到特定页面类型，使用默认SEO数据
        if not seo_data:
            seo_data = self._get_default_seo_data(context, request, blog_setting)

        # 将JSON-LD数据转换为脚本标签
        json_ld_script = f'<script type="application/ld+json">{json.dumps(seo_data.get("json_ld", {}), ensure_ascii=False, indent=4)}</script>'

        # 返回完整的SEO HTML代码
        return f"""
        <title>{seo_data.get("title", "")}</title>
        <meta name="description" content="{seo_data.get("description", "")}">
        <meta name="keywords" content="{seo_data.get("keywords", "")}">
        {seo_data.get("meta_tags", "")}
        {json_ld_script}
        """


# 实例化插件，自动注册到系统
plugin = SeoOptimizerPlugin()
