#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Cookie管理器
支持多个cookies的管理、验证和轮换使用
"""

import json
import os
import time
import random
from typing import Dict, List, Optional, Tuple
from datetime import datetime, timedelta
import logging

from .models import CookieInfo, CookieStats

logger = logging.getLogger(__name__)

class CookieManager:
    """Cookie管理器"""
    
    def __init__(self, config_path: str = "config/cookies.json"):
        self.config_path = config_path
        self.cookies: Dict[str, CookieInfo] = {}
        self.current_cookie: Optional[str] = None
        self.max_failures = 3  # 最大失败次数
        self.rotation_interval = 300  # 轮换间隔（秒）
        self.load_cookies()
    
    def load_cookies(self) -> None:
        """加载cookies配置"""
        try:
            if os.path.exists(self.config_path):
                with open(self.config_path, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    
                for cookie_data in data.get('cookies', []):
                    cookie_info = CookieInfo(
                        name=cookie_data['name'],
                        cookie_string=cookie_data['cookie_string'],
                        last_used=cookie_data.get('last_used', datetime.now().isoformat()),
                        use_count=cookie_data.get('use_count', 0),
                        is_valid=cookie_data.get('is_valid', True),
                        failure_count=cookie_data.get('failure_count', 0),
                        user_info=cookie_data.get('user_info')
                    )
                    self.cookies[cookie_info.name] = cookie_info
                    
                logger.info(f"加载了 {len(self.cookies)} 个cookies")
            else:
                logger.warning(f"Cookie配置文件不存在: {self.config_path}")
                self._create_default_config()
        except Exception as e:
            logger.error(f"加载cookies失败: {str(e)}")
            self._create_default_config()
    
    def _create_default_config(self) -> None:
        """创建默认配置文件"""
        os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
        default_config = {
            "cookies": [
                {
                    "name": "default",
                    "cookie_string": "请在此处填入您的小红书cookie",
                    "last_used": datetime.now().isoformat(),
                    "use_count": 0,
                    "is_valid": True,
                    "failure_count": 0,
                    "user_info": None
                }
            ]
        }
        with open(self.config_path, 'w', encoding='utf-8') as f:
            json.dump(default_config, f, ensure_ascii=False, indent=2)
        logger.info(f"创建默认配置文件: {self.config_path}")
    
    def save_cookies(self) -> None:
        """保存cookies配置"""
        try:
            cookies_data = []
            for cookie_info in self.cookies.values():
                cookies_data.append({
                    'name': cookie_info.name,
                    'cookie_string': cookie_info.cookie_string,
                    'last_used': cookie_info.last_used.isoformat(),
                    'use_count': cookie_info.use_count,
                    'is_valid': cookie_info.is_valid,
                    'failure_count': cookie_info.failure_count,
                    'user_info': cookie_info.user_info
                })
            
            config_data = {'cookies': cookies_data}
            os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
            with open(self.config_path, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, ensure_ascii=False, indent=2)
            logger.debug("保存cookies配置成功")
        except Exception as e:
            logger.error(f"保存cookies配置失败: {str(e)}")
    
    def add_cookie(self, name: str, cookie_string: str, user_info: Optional[Dict] = None) -> bool:
        """添加新的cookie"""
        if name in self.cookies:
            logger.warning(f"Cookie名称 '{name}' 已存在")
            return False
        
        cookie_info = CookieInfo(
            name=name,
            cookie_string=cookie_string,
            user_info=user_info
        )
        self.cookies[name] = cookie_info
        self.save_cookies()
        logger.info(f"添加新cookie: {name}")
        return True
    
    def remove_cookie(self, name: str) -> bool:
        """删除cookie"""
        if name not in self.cookies:
            logger.warning(f"Cookie名称 '{name}' 不存在")
            return False
        
        del self.cookies[name]
        if self.current_cookie == name:
            self.current_cookie = None
        self.save_cookies()
        logger.info(f"删除cookie: {name}")
        return True
    
    def get_valid_cookies(self) -> List[str]:
        """获取有效的cookie名称列表"""
        return [name for name, cookie_info in self.cookies.items() 
                if cookie_info.is_valid and cookie_info.failure_count < self.max_failures]
    
    def get_cookie(self, name: Optional[str] = None) -> Optional[CookieInfo]:
        """获取指定或最优的cookie"""
        if name:
            return self.cookies.get(name) if name in self.cookies else None
        
        # 获取最优cookie
        valid_cookies = self.get_valid_cookies()
        if not valid_cookies:
            logger.error("没有可用的cookies")
            return None
        
        # 选择策略：优先使用失败次数少、使用次数少的cookie
        best_cookie = None
        best_score = float('inf')
        
        for cookie_name in valid_cookies:
            cookie_info = self.cookies[cookie_name]
            # 计算评分：失败次数 * 10 + 使用次数 + 时间因子
            time_factor = (datetime.now() - cookie_info.last_used).total_seconds() / 3600  # 小时
            score = cookie_info.failure_count * 10 + cookie_info.use_count - time_factor
            
            if score < best_score:
                best_score = score
                best_cookie = cookie_info
        
        return best_cookie
    
    def get_cookie_string(self, name: Optional[str] = None) -> Optional[str]:
        """获取cookie字符串"""
        cookie_info = self.get_cookie(name)
        if cookie_info:
            # 更新使用信息
            cookie_info.last_used = datetime.now()
            cookie_info.use_count += 1
            self.current_cookie = cookie_info.name
            self.save_cookies()
            return cookie_info.cookie_string
        return None
    
    def mark_cookie_failure(self, name: Optional[str] = None) -> None:
        """标记cookie使用失败"""
        cookie_name = name or self.current_cookie
        if cookie_name and cookie_name in self.cookies:
            cookie_info = self.cookies[cookie_name]
            cookie_info.failure_count += 1
            
            if cookie_info.failure_count >= self.max_failures:
                cookie_info.is_valid = False
                logger.warning(f"Cookie '{cookie_name}' 已失效")
            
            self.save_cookies()
    
    def mark_cookie_success(self, name: Optional[str] = None) -> None:
        """标记cookie使用成功"""
        cookie_name = name or self.current_cookie
        if cookie_name and cookie_name in self.cookies:
            cookie_info = self.cookies[cookie_name]
            cookie_info.failure_count = 0  # 重置失败次数
            cookie_info.is_valid = True
            self.save_cookies()
    
    def get_random_cookie(self) -> Optional[CookieInfo]:
        """随机获取一个有效的cookie"""
        valid_cookies = self.get_valid_cookies()
        if not valid_cookies:
            return None
        
        cookie_name = random.choice(valid_cookies)
        return self.cookies[cookie_name]
    
    def get_statistics(self) -> CookieStats:
        """获取cookie使用统计"""
        total_cookies = len(self.cookies)
        valid_cookies = len(self.get_valid_cookies())
        invalid_cookies = total_cookies - valid_cookies
        
        cookie_details = []
        for name, cookie_info in self.cookies.items():
            cookie_details.append({
                'name': name,
                'is_valid': cookie_info.is_valid,
                'use_count': cookie_info.use_count,
                'failure_count': cookie_info.failure_count,
                'last_used': cookie_info.last_used.isoformat()
            })
        
        return CookieStats(
            total_cookies=total_cookies,
            valid_cookies=valid_cookies,
            invalid_cookies=invalid_cookies,
            current_cookie=self.current_cookie,
            cookie_details=cookie_details
        )
    
    def refresh_cookie_validity(self) -> None:
        """刷新cookie有效性（重置失败次数）"""
        for cookie_info in self.cookies.values():
            if cookie_info.failure_count < self.max_failures:
                cookie_info.is_valid = True
                cookie_info.failure_count = 0
        self.save_cookies()
        logger.info("已刷新所有cookie的有效性")
    
    def rotate_cookies(self) -> None:
        """轮换cookies（可定期调用）"""
        if len(self.get_valid_cookies()) <= 1:
            return
        
        # 如果当前cookie使用时间过长，切换到其他cookie
        if self.current_cookie:
            current_cookie_info = self.cookies.get(self.current_cookie)
            if current_cookie_info:
                time_since_last_use = (datetime.now() - current_cookie_info.last_used).total_seconds()
                if time_since_last_use > self.rotation_interval:
                    self.current_cookie = None
                    logger.info("Cookie轮换：切换到其他cookie") 