"""
发布服务 (支持用户隔离)
"""
import json
import os
import re
import tempfile
import httpx
from datetime import datetime
from pathlib import Path
from typing import Optional, List, Dict, Any
from loguru import logger
from app.core.config import settings
from app.core.paths import get_user_cookie_dir, get_platform_cookie_path, get_legacy_cookie_dir, get_legacy_cookie_path
from app.services.storage import storage_service

# Import platform uploaders
from .uploader.bilibili_uploader import BilibiliUploader
from .uploader.douyin_uploader import DouyinUploader
from .uploader.xiaohongshu_uploader import XiaohongshuUploader
from .uploader.weixin_uploader import WeixinUploader


class PublishService:
    """Social media publishing service (with user isolation)"""

    # 支持的平台配置
    PLATFORMS: Dict[str, Dict[str, Any]] = {
        "douyin": {"name": "抖音", "url": "https://creator.douyin.com/", "enabled": True},
        "weixin": {"name": "微信视频号", "url": "https://channels.weixin.qq.com/", "enabled": True},
        "bilibili": {"name": "B站", "url": "https://member.bilibili.com/platform/upload/video/frame", "enabled": True},
        "xiaohongshu": {"name": "小红书", "url": "https://creator.xiaohongshu.com/", "enabled": True},
    }

    COOKIE_DOMAINS: Dict[str, str] = {
        "douyin": ".douyin.com",
        "weixin": ".weixin.qq.com",
        "xiaohongshu": ".xiaohongshu.com",
    }
    
    def __init__(self) -> None:
        # 存储活跃的登录会话，用于跟踪登录状态
        # key 格式: "{user_id}_{platform}" 或 "{platform}" (兼容旧版)
        self.active_login_sessions: Dict[str, Any] = {}
    
    def _get_cookies_dir(self, user_id: Optional[str] = None) -> Path:
        """获取 Cookie 目录 (支持用户隔离)"""
        if user_id:
            return get_user_cookie_dir(user_id)
        return get_legacy_cookie_dir()
    
    def _get_cookie_path(self, platform: str, user_id: Optional[str] = None) -> Path:
        """获取 Cookie 文件路径 (支持用户隔离)"""
        if user_id:
            return get_platform_cookie_path(user_id, platform)
        return get_legacy_cookie_path(platform)
    
    def _get_session_key(self, platform: str, user_id: Optional[str] = None) -> str:
        """获取会话 key"""
        if user_id:
            return f"{user_id}_{platform}"
        return platform
    
    def get_accounts(self, user_id: Optional[str] = None) -> List[Dict[str, Any]]:
        """Get list of platform accounts with login status"""
        accounts = []
        for pid, pinfo in self.PLATFORMS.items():
            cookie_file = self._get_cookie_path(pid, user_id)
            accounts.append({
                "platform": pid,
                "name": pinfo["name"],
                "logged_in": cookie_file.exists(),
                "enabled": pinfo.get("enabled", True)
            })
        return accounts
    
    async def publish(
        self,
        video_path: str,
        platform: str,
        title: str,
        tags: List[str],
        description: str = "",
        publish_time: Optional[datetime] = None,
        user_id: Optional[str] = None,
        **kwargs: Any
    ) -> Dict[str, Any]:
        """
        Publish video to specified platform
        
        Args:
            video_path: Path to video file
            platform: Platform ID (bilibili, douyin, etc.)
            title: Video title
            tags: List of tags
            description: Video description
            publish_time: Scheduled publish time (None = immediate)
            user_id: User ID for cookie isolation
            **kwargs: Additional platform-specific parameters
            
        Returns:
            dict: Publish result
        """
        # Validate platform
        if platform not in self.PLATFORMS:
            logger.error(f"[发布] 不支持的平台: {platform}")
            return {
                "success": False,
                "message": f"不支持的平台: {platform}",
                "platform": platform
            }
        
        # Get account file path (with user isolation)
        account_file = self._get_cookie_path(platform, user_id)
        
        if not account_file.exists():
            return {
                "success": False,
                "message": f"请先登录 {self.PLATFORMS[platform]['name']}",
                "platform": platform
            }
        
        logger.info(f"[发布] 平台: {self.PLATFORMS[platform]['name']}")
        logger.info(f"[发布] 视频: {video_path}")
        logger.info(f"[发布] 标题: {title}")
        logger.info(f"[发布] 用户: {user_id or 'legacy'}")

        temp_file = None
        try:
            # 处理视频路径
            if video_path.startswith('http://') or video_path.startswith('https://'):
                # 尝试从 URL 解析 bucket 和 path，直接使用本地文件
                local_video_path = None

                # URL 格式: .../storage/v1/object/sign/{bucket}/{path}?token=...
                match = re.search(r'/storage/v1/object/sign/([^/]+)/(.+?)\?', video_path)
                if match:
                    bucket = match.group(1)
                    storage_path = match.group(2)
                    logger.info(f"[发布] 解析 URL: bucket={bucket}, path={storage_path}")

                    # 尝试获取本地文件路径
                    local_video_path = storage_service.get_local_file_path(bucket, storage_path)

                if local_video_path and os.path.exists(local_video_path):
                    logger.info(f"[发布] 直接使用本地文件: {local_video_path}")
                else:
                    # 本地文件不存在，通过 HTTP 下载
                    logger.info(f"[发布] 本地文件不存在，通过 HTTP 下载...")
                    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
                    temp_file.close()

                    # 将公网 URL 替换为内网 URL
                    download_url = video_path
                    if settings.SUPABASE_PUBLIC_URL and settings.SUPABASE_URL:
                        public_url = settings.SUPABASE_PUBLIC_URL.rstrip('/')
                        internal_url = settings.SUPABASE_URL.rstrip('/')
                        download_url = video_path.replace(public_url, internal_url)

                    async with httpx.AsyncClient(timeout=httpx.Timeout(None)) as client:
                        async with client.stream("GET", download_url) as resp:
                            resp.raise_for_status()
                            with open(temp_file.name, 'wb') as f:
                                async for chunk in resp.aiter_bytes():
                                    f.write(chunk)
                    local_video_path = temp_file.name
                    logger.info(f"[发布] 视频已下载到: {local_video_path}")
            else:
                # 本地相对路径
                local_video_path = str(settings.BASE_DIR.parent / video_path)

            # Select appropriate uploader
            if platform == "bilibili":
                uploader = BilibiliUploader(
                    title=title,
                    file_path=local_video_path,
                    tags=tags,
                    publish_date=publish_time,
                    account_file=str(account_file),
                    description=description,
                    tid=kwargs.get('tid', 122),
                    copyright=kwargs.get('copyright', 1)
                )
            elif platform == "douyin":
                uploader = DouyinUploader(
                    title=title,
                    file_path=local_video_path,
                    tags=tags,
                    publish_date=publish_time,
                    account_file=str(account_file),
                    description=description,
                    user_id=user_id,
                )
            elif platform == "xiaohongshu":
                uploader = XiaohongshuUploader(
                    title=title,
                    file_path=local_video_path,
                    tags=tags,
                    publish_date=publish_time,
                    account_file=str(account_file),
                    description=description,
                    user_id=user_id,
                )
            elif platform == "weixin":
                uploader = WeixinUploader(
                    title=title,
                    file_path=local_video_path,
                    tags=tags,
                    publish_date=publish_time,
                    account_file=str(account_file),
                    description=description,
                    user_id=user_id,
                )
            else:
                logger.warning(f"[发布] {platform} 上传功能尚未实现")
                return {
                    "success": False,
                    "message": f"{self.PLATFORMS[platform]['name']} 上传功能开发中",
                    "platform": platform
                }
            
            # Execute upload
            result = await uploader.main()
            result['platform'] = platform
            return result

        except Exception as e:
            logger.exception(f"[发布] 上传异常: {e}")
            return {
                "success": False,
                "message": f"上传异常: {str(e)}",
                "platform": platform
            }
        finally:
            # 清理临时文件
            if temp_file and os.path.exists(temp_file.name):
                try:
                    os.remove(temp_file.name)
                    logger.info(f"[发布] 已清理临时文件: {temp_file.name}")
                except Exception as e:
                    logger.warning(f"[发布] 清理临时文件失败: {e}")
    
    async def login(self, platform: str, user_id: Optional[str] = None) -> Dict[str, Any]:
        """
        启动QR码登录流程

        Args:
            platform: 平台 ID
            user_id: 用户 ID (用于 Cookie 隔离)

        Returns:
            dict: 包含二维码base64图片
        """
        if platform not in self.PLATFORMS:
            return {"success": False, "message": "不支持的平台"}

        try:
            from .qr_login_service import QRLoginService

            # 获取用户专属的 Cookie 目录
            cookies_dir = self._get_cookies_dir(user_id)

            # 清理旧的活跃会话（避免残留会话干扰新登录）
            session_key = self._get_session_key(platform, user_id)
            if session_key in self.active_login_sessions:
                old_service = self.active_login_sessions.pop(session_key)
                try:
                    await old_service._cleanup()
                except Exception:
                    pass

            # 创建QR登录服务
            qr_service = QRLoginService(platform, cookies_dir)

            # 存储活跃会话 (带用户隔离)
            self.active_login_sessions[session_key] = qr_service

            # 启动登录并获取二维码
            result = await qr_service.start_login()
            
            return result
            
        except Exception as e:
            logger.exception(f"[登录] QR码登录失败: {e}")
            return {
                "success": False,
                "message": f"登录失败: {str(e)}"
            }

    def get_login_session_status(self, platform: str, user_id: Optional[str] = None) -> Dict[str, Any]:
        """获取活跃登录会话的状态（仅用于扫码轮询）"""
        session_key = self._get_session_key(platform, user_id)

        # 只检查活跃的扫码会话，不检查 Cookie 文件
        # Cookie 文件检查会导致"重新登录"时误判为已登录
        if session_key in self.active_login_sessions:
            qr_service = self.active_login_sessions[session_key]
            status = qr_service.get_login_status()

            # 如果登录成功且Cookie已保存，清理会话
            if status["success"] and status["cookies_saved"]:
                del self.active_login_sessions[session_key]
                return {"success": True, "message": "登录成功"}

            # 刷脸验证：传递新二维码给前端
            result: Dict[str, Any] = {"success": False, "message": "等待扫码..."}
            if status.get("face_verify_qr"):
                result["face_verify_qr"] = status["face_verify_qr"]
            return result

        # 没有活跃会话 → 返回 False（前端不应在无会话时轮询）
        return {"success": False, "message": "无活跃登录会话"}
    
    def logout(self, platform: str, user_id: Optional[str] = None) -> Dict[str, Any]:
        """
        Logout from platform (delete cookie file)
        """
        if platform not in self.PLATFORMS:
            return {"success": False, "message": "不支持的平台"}
            
        try:
            session_key = self._get_session_key(platform, user_id)
            
            # 1. 移除活跃会话
            if session_key in self.active_login_sessions:
                del self.active_login_sessions[session_key]
                
            # 2. 删除Cookie文件
            cookie_file = self._get_cookie_path(platform, user_id)
            if cookie_file.exists():
                cookie_file.unlink()
                logger.info(f"[登出] {platform} Cookie已删除 (user: {user_id or 'legacy'})")
                
            return {"success": True, "message": "已注销"}
            
        except Exception as e:
            logger.exception(f"[登出] 失败: {e}")
            return {"success": False, "message": f"注销失败: {str(e)}"}

    async def save_cookie_string(self, platform: str, cookie_string: str, user_id: Optional[str] = None) -> Dict[str, Any]:
        """
        保存从客户端浏览器提取的Cookie字符串
        
        Args:
            platform: 平台ID
            cookie_string: document.cookie 格式的Cookie字符串
            user_id: 用户 ID (用于 Cookie 隔离)
        """
        try:
            if platform not in self.PLATFORMS:
                return {
                    "success": False,
                    "message": f"不支持的平台: {platform}",
                }

            account_file = self._get_cookie_path(platform, user_id)
            
            # 解析Cookie字符串
            cookie_dict: Dict[str, str] = {}
            for item in cookie_string.split(';'):
                item = item.strip()
                if not item:
                    continue
                if '=' in item:
                    name, value = item.split('=', 1)
                    cookie_dict[name.strip()] = value.strip()

            if not cookie_dict:
                return {
                    "success": False,
                    "message": "Cookie 为空，请确认已完成登录",
                }
            
            # 对B站进行特殊处理
            if platform == "bilibili":
                bilibili_cookies = {}
                required_fields = ['SESSDATA', 'bili_jct', 'DedeUserID', 'DedeUserID__ckMd5']
                
                for field in required_fields:
                    if field in cookie_dict:
                        bilibili_cookies[field] = cookie_dict[field]
                
                if len(bilibili_cookies) < 3:
                    return {
                        "success": False,
                        "message": "Cookie不完整，请确保已登录"
                    }
                payload: Any = bilibili_cookies
            else:
                cookie_domain = self.COOKIE_DOMAINS.get(platform, "")
                if not cookie_domain:
                    platform_url = self.PLATFORMS.get(platform, {}).get("url", "")
                    host = re.sub(r"^https?://", "", platform_url).strip("/")
                    cookie_domain = f".{host}" if host else ""

                storage_cookies = []
                for name, value in cookie_dict.items():
                    if not name:
                        continue
                    storage_cookies.append({
                        "name": name,
                        "value": value,
                        "domain": cookie_domain,
                        "path": "/",
                        "httpOnly": False,
                        "secure": True,
                        "sameSite": "Lax",
                        "expires": -1,
                    })

                payload = {
                    "cookies": storage_cookies,
                    "origins": [],
                }
            
            # 确保目录存在
            account_file.parent.mkdir(parents=True, exist_ok=True)
            
            # 保存Cookie
            with open(account_file, 'w', encoding='utf-8') as f:
                json.dump(payload, f, indent=2)
            
            logger.success(f"[登录] {platform} Cookie已保存 (user: {user_id or 'legacy'})")
            
            return {
                "success": True,
                "message": f"{self.PLATFORMS[platform]['name']} 登录成功"
            }
            
        except Exception as e:
            logger.exception(f"[登录] Cookie保存失败: {e}")
            return {
                "success": False,
                "message": f"Cookie保存失败: {str(e)}"
            }
