from bs4 import BeautifulSoup
import re
from diona.tools.crawler.base_spider import BaseSpider
from .models import ZhihuParseResult


class ZhihuSpider(BaseSpider):
    """知乎爬虫实现类"""
    
    def supports_url(self, url: str) -> bool:
        """
        校验链接
        
        Args:
            url: 要校验的URL
            
        Returns:
            是否支持该URL
        """
        return 'zhihu.com' in url and (self._is_zhihu_column_url(url) or self._is_zhihu_answer_url(url))
    
    def requires_login(self) -> bool:
        """
        判断是否需要登录
        
        Returns:
            是否需要登录（知乎需要登录）
        """
        return True
    
    def _is_zhihu_column_url(self, url: str) -> bool:
        """
        判断是否为知乎专栏URL
        
        Args:
            url: 要判断的URL
            
        Returns:
            是否为知乎专栏URL
        """
        return 'zhuanlan.zhihu.com/p/' in url
    
    def _is_zhihu_answer_url(self, url: str) -> bool:
        """
        判断是否为知乎回答URL
        
        Args:
            url: 要判断的URL
            
        Returns:
            是否为知乎回答URL
        """
        return 'answer' in url
    
    def _get_login_url(self) -> str:
        """
        获取知乎登录页面URL
        
        Returns:
            登录页面URL
        """
        return 'https://www.zhihu.com/signin'
    
    def do_action(self, page) -> str:
        """
        执行浏览器动作，获取原始响应数据
        
        Args:
            page: Playwright页面对象
            
        Returns:
            原始响应数据（HTML内容）
        """
        # 等待页面加载完成
        page.wait_for_load_state('networkidle', timeout=60000)
        
        # 尝试点击展开按钮（如果有的话）
        try:
            expand_buttons = page.query_selector_all('button.ContentItem-expandButton')
            print(f"找到 {len(expand_buttons)} 个展开按钮")
            for button in expand_buttons:
                if '展开' in button.inner_text() or '显示全部' in button.inner_text():
                    try:
                        
                        button.click()
                        print(f"点击展开按钮: {button.inner_text()}")
                        page.wait_for_timeout(1000)  # 等待展开内容加载
                    except Exception as e:
                        print(f"点击展开按钮失败: {e}")
        except Exception as e:
            print(f"查找展开按钮失败: {e}")
        
        # 获取页面HTML内容
        content = page.content()
        
        return content
    
    def process_content(self, content: str) -> ZhihuParseResult:
        """
        处理爬取到的原始内容，将其解析为结构化数据
        
        Args:
            content: 原始HTML内容
            
        Returns:
            知乎解析结果对象
        """
        # 使用BeautifulSoup解析HTML
        soup = BeautifulSoup(content, 'html.parser')
        
        # 提取标题
        title = ''
        try:
            # 主要从title标签中提取
            title_elem = soup.find('title')
            if title_elem:
                title_text = title_elem.get_text().strip()
                
                # 清理标题：移除前面的私信信息和后面的"- 知乎"
                # 格式: (4 封私信 / 80 条消息) 卖掉房子去租房一定是稳赚的，但大聪明才会这么干 - 知乎
                
                # 使用正则表达式提取
                import re
                match = re.search(r'\)\s*(.+?)\s*-\s*知乎', title_text)
                if match:
                    title = match.group(1).strip()
                else:
                    # 使用简单分割
                    if ')' in title_text:
                        right_paren_index = title_text.find(')')
                        after_paren = title_text[right_paren_index + 1:].strip()
                        title = after_paren.replace(' - 知乎', '').strip()
                    else:
                        title = title_text.replace(' - 知乎', '').strip()
            
            # 如果还没有找到标题，尝试其他选择器
            if not title:
                title_selectors = [
                    'h1.Post-Title',
                    'h1.QuestionHeader-title',
                    'h1',
                    '.Post-Title',
                    '.QuestionHeader-title',
                    'h1.TitleImage',
                    '.TitleImage',
                    '.Post-Header',
                    '.QuestionHeader'
                ]
                
                for selector in title_selectors:
                    title_elem = soup.select_one(selector)
                    if title_elem:
                        title_text = title_elem.get_text().strip()
                        if title_text and title_text != '知乎回答' and title_text != '知乎':
                            title = title_text
                            break
        except Exception as e:
            print(f"提取标题失败: {e}")
        
        # 提取作者
        author = ''
        try:
            author_selectors = [
                '.AuthorInfo-name',
                '.UserLink-link',
                '.AuthorInfo',
                '.UserLink',
                '.Post-Author',
                '.AnswerAuthor',
                '.AuthorInfo-head',
                '.UserLink',
                '.AuthorInfo-content',
                '.ContentItem-meta',
                '.AuthorInfo .UserLink',
                '.Post-Author .UserLink',
                '.ColumnAuthor',
                '.Author'
            ]
            
            for selector in author_selectors:
                author_elem = soup.select_one(selector)
                if author_elem:
                    author_text = author_elem.get_text().strip()
                    if author_text and author_text != '匿名用户':
                        author = author_text
                        break
            
            # 如果还没有找到作者，尝试从meta信息中提取
            if not author:
                meta_author = soup.find('meta', {'name': 'author'})
                if meta_author:
                    author = meta_author.get('content', '').strip()
        except Exception as e:
            print(f"提取作者失败: {e}")
        
        # 提取日期位置信息
        date_position = ''
        try:
            date_selectors = [
                '.ContentItem-time',
                '.AnswerCard-time',
                '.AuthorInfo-meta'
            ]
            
            for selector in date_selectors:
                date_elem = soup.select_one(selector)
                if date_elem:
                    date_text = date_elem.get_text().strip()
                    if date_text:
                        date_position = date_text
                        break
        except Exception as e:
            print(f"提取日期位置失败: {e}")
        
        # 提取图片 - 只提取文章内容中的相关图片
        images = []
        try:
            # 首先找到文章内容区域
            content_selectors = [
                '.RichContent-inner',  # 知乎回答内容
                '.Post-RichText',      # 知乎专栏文章内容
                '.ContentItem-answer', # 回答容器
                '.AnswerCard',         # 回答卡片
                'article',             # 文章标签
                '.PostContent'         # 文章内容
            ]
            
            content_area = None
            for selector in content_selectors:
                content_area = soup.select_one(selector)
                if content_area:
                    print(f"图片提取使用选择器: '{selector}'")
                    break
            
            # 如果没有找到特定内容区域，使用整个页面
            if not content_area:
                content_area = soup
                print("图片提取使用整个页面")
            
            # 只从内容区域提取图片
            img_elems = content_area.select('img')
            print(f"在内容区域找到 {len(img_elems)} 个图片元素")
            
            for img_elem in img_elems:
                # 尝试获取图片的真实URL
                img_url = img_elem.get('src')
                if not img_url or img_url.startswith('data:'):
                    img_url = img_elem.get('data-src')
                if not img_url or img_url.startswith('data:'):
                    img_url = img_elem.get('data-original')
                if not img_url or img_url.startswith('data:'):
                    img_url = img_elem.get('data-actualsrc')
                
                # 过滤掉无效和无关的图片
                if img_url and not img_url.startswith('data:'):
                    # 过滤掉常见的无关图片
                    if any(unwanted in img_url for unwanted in [
                        'avatar',  # 头像
                        'icon',    # 图标
                        'logo',    # Logo
                        'button',  # 按钮图片
                        'badge',   # 徽章
                        'emoji',   # 表情
                        'spinner', # 加载动画
                        'placeholder', # 占位符
                        'default', # 默认图片
                        'anonymous', # 匿名用户头像
                        'v2-',     # 知乎头像格式
                        '80/v2',   # 小尺寸头像
                        '50/v2',   # 小尺寸头像
                        '40/v2',   # 小尺寸头像
                        '30/v2',   # 小尺寸头像
                        '20/v2',   # 小尺寸头像
                        'zhstatic', # 知乎静态资源
                        'heifetz',  # 知乎静态资源
                        'favicon',  # 网站图标
                        'sprite',   # 雪碧图
                        'background', # 背景图片
                        'ad.',      # 广告图片
                        'ads.',     # 广告图片
                        'banner',   # 横幅广告
                        'promo',    # 推广图片
                        'recommend', # 推荐图片
                        'sidebar',  # 侧边栏图片
                        'footer',   # 页脚图片
                        'header',   # 页头图片
                        'navigation', # 导航图片
                        'menu',     # 菜单图片
                        'toolbar',  # 工具栏图片
                        'widget',   # 小组件图片
                        'social',   # 社交分享图片
                        'share',    # 分享按钮图片
                        'comment',  # 评论相关图片
                        'vote',     # 投票相关图片
                        'follow',   # 关注相关图片
                        'collection', # 收藏相关图片
                        'report',   # 举报相关图片
                        'copyright', # 版权相关图片
                        'legal',    # 法律相关图片
                        'privacy',  # 隐私相关图片
                        'terms',    # 条款相关图片
                        'cookie',   # Cookie相关图片
                        'disclaimer' # 免责声明相关图片
                    ]):
                        print(f"过滤掉无关图片: {img_url}")
                        continue
                    
                    # 检查图片尺寸（如果可以从URL中推断）
                    # 通常文章内容图片会有较大的尺寸标识
                    if any(size_indicator in img_url for size_indicator in [
                        '720w', '1080w', 'xl.', 'large', 'big',
                        'original', 'source', 'content', 'article'
                    ]):
                        images.append(img_url)
                        print(f"保留内容图片: {img_url}")
                    else:
                        # 对于没有明确尺寸标识的图片，检查父元素的上下文
                        parent_classes = ' '.join(img_elem.find_parent().get('class', []))
                        if any(content_indicator in parent_classes for content_indicator in [
                            'content', 'article', 'post', 'answer', 'rich', 'text'
                        ]):
                            images.append(img_url)
                            print(f"保留上下文图片: {img_url}")
                        else:
                            print(f"过滤掉小图片: {img_url}")
            
            print(f"最终保留 {len(images)} 张内容相关图片")
            
        except Exception as e:
            print(f"提取图片失败: {e}")
        
        # 提取纯文本内容
        text_content = ''
        try:
            # 首先尝试提取知乎回答的主体内容
            content_selectors = [
                '.RichContent-inner',  # 知乎回答内容
                '.Post-RichText',      # 知乎专栏文章内容
                '.ContentItem-answer', # 回答容器
                '.AnswerCard',         # 回答卡片
                'article',             # 文章标签
                '.PostContent'         # 文章内容
            ]
            
            # 尝试从特定选择器提取内容
            main_content = None
            for selector in content_selectors:
                main_content = soup.select_one(selector)
                if main_content:
                    print(f"使用选择器 '{selector}' 找到主要内容")
                    break
            
            # 如果没有找到特定内容区域，使用整个页面
            if not main_content:
                main_content = soup
                print("未找到特定内容区域，使用整个页面")
            
            # 移除不需要的元素
            unwanted_selectors = [
                'script', 'style',  # 脚本和样式
                '.Footer', '.footer',  # 页脚
                '.Header', '.header',  # 页头
                '.Ad', '.ad', '.advertisement',  # 广告
                '.Recommendations', '.recommend',  # 推荐内容
                '.RelatedQuestions', '.related',  # 相关问题
                '.Comment', '.comment',  # 评论
                '.SideBar', '.sidebar',  # 侧边栏
                '.Navigation', '.nav',  # 导航
                '.UserCard', '.usercard',  # 用户卡片
                '.ActionBar', '.actionbar',  # 操作栏
                '.Button', '.button',  # 按钮
                '.Modal', '.modal',  # 弹窗
                '.Tooltip', '.tooltip',  # 提示
                '.Pagination', '.pagination',  # 分页
                '.Share', '.share',  # 分享
                '.Follow', '.follow',  # 关注
                '.Vote', '.vote',  # 投票
                '.Collection', '.collection',  # 收藏
                '.Report', '.report',  # 举报
                '.Copyright', '.copyright',  # 版权
                '.Legal', '.legal',  # 法律信息
                '.Privacy', '.privacy',  # 隐私
                '.Terms', '.terms',  # 条款
                '.Cookie', '.cookie',  # Cookie
                '.Disclaimer', '.disclaimer'  # 免责声明
            ]
            
            # 移除不需要的元素
            for selector in unwanted_selectors:
                for elem in main_content.select(selector):
                    elem.decompose()
            
            # 获取纯文本内容
            text_content = main_content.get_text(separator='\n')
            
            # 清理文本：移除多余的空行和空白字符
            lines = []
            for line in text_content.split('\n'):
                line = line.strip()
                if line:  # 只保留非空行
                    # 移除常见的无关文本
                    if not any(unwanted in line for unwanted in [
                        '私信', '条消息', '关注问题', '写回答', '邀请回答', 
                        '条评论', '分享', '收藏', '喜欢', '关注', '关注者',
                        '被浏览', '相关问题', '大家都在搜', '换一换', '广告',
                        '帮助中心', '关于知乎', '下载知乎', '知乎招聘', '知乎指南',
                        '京ICP证', '京公网安备', '互联网新闻信息服务许可证',
                        '广播电视节目制作经营许可证', '互联网宗教信息服务许可证',
                        '服务热线', 'Investor Relations', '©', '违法和不良信息举报',
                        '举报邮箱', '想来知乎工作', '发送邮件'
                    ]):
                        lines.append(line)
            
            # 重新组合文本
            text_content = '\n'.join(lines)
            
            # 进一步清理文本
            text_content = re.sub(r'\n+', '\n', text_content)
            text_content = re.sub(r'\s+', ' ', text_content)
            text_content = text_content.strip()
            
            # 如果内容过长，可能是包含了太多无关内容，尝试更精确的提取
            if len(text_content) > 5000:
                print(f"内容过长({len(text_content)}字符)，尝试更精确提取...")
                # 尝试只提取回答正文部分
                answer_text = ''
                answer_paragraphs = main_content.select('p, div')
                for para in answer_paragraphs:
                    para_text = para.get_text().strip()
                    if para_text and len(para_text) > 10:  # 只保留有意义的段落
                        # 检查是否包含回答内容的关键词
                        if any(keyword in para_text for keyword in [
                            '大道理', '工作中', '见闻', '保真', '退休', '大爷',
                            '配眼镜', '闲聊', '工资', '退休金', '政策', '县城',
                            '收入', '最低工资', '年轻人', '老年人', '既得利益者'
                        ]):
                            answer_text += para_text + '\n'
                
                if answer_text:
                    text_content = answer_text.strip()
                    print(f"精确提取后内容长度: {len(text_content)}字符")
                
        except Exception as e:
            print(f"提取文本内容失败: {e}")
        
        # 返回知乎解析结果对象
        return ZhihuParseResult(
            title=title,
            author=author,
            date_position=date_position,
            content=text_content,
            images=images
        )