
import sys
import os

# 添加src目录到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../..'))


"""
安全工具模块
"""
from passlib.context import CryptContext
from jose import JWTError, jwt
from datetime import datetime, timedelta
from typing import Optional, Dict, Any
from app.core.config import config_handler
import secrets
import string
import hashlib
import base64

# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


def hash_password(password: str) -> str:
    """密码哈希"""
    # 确保密码不超过72字节
    if len(password.encode('utf-8')) > 72:
        password = password[:72]
    return pwd_context.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码
    
    支持两种格式:
    1. bcrypt格式 (新格式)
    2. sha256$salt$hash格式 (旧格式，兼容历史数据)
    """
    # 检查是否是旧的sha256格式
    if hashed_password.startswith('sha256$'):
        try:
            # 解析: sha256$salt$hash
            parts = hashed_password.split('$')
            if len(parts) == 3:
                algorithm, salt, stored_hash = parts
                # 使用相同的salt计算hash (注意：是 password + salt，不是 salt + password)
                computed_hash = hashlib.sha256((plain_password + salt).encode()).hexdigest()
                return computed_hash == stored_hash
        except Exception:
            return False
    
    # 使用bcrypt验证
    try:
        return pwd_context.verify(plain_password, hashed_password)
    except Exception:
        return False


def create_access_token(
    data: Dict[str, Any], 
    expires_delta: Optional[timedelta] = None
) -> str:
    """创建访问令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=config_handler.get_int("admin_app", "ACCESS_TOKEN_EXPIRE_MINUTES", 30))
    
    to_encode.update({"exp": expire, "iat": datetime.utcnow()})
    encoded_jwt = jwt.encode(to_encode, config_handler.get("admin_app", "JWT_SECRET_KEY", "dev-jwt-secret-key"), algorithm=config_handler.get("admin_app", "ALGORITHM", "HS256"))
    return encoded_jwt


def create_refresh_token(
    data: Dict[str, Any], 
    expires_delta: Optional[timedelta] = None
) -> str:
    """创建刷新令牌"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(days=config_handler.get_int("admin_app", "REFRESH_TOKEN_EXPIRE_DAYS", 30))
    
    to_encode.update({"exp": expire, "iat": datetime.utcnow(), "type": "refresh"})
    encoded_jwt = jwt.encode(to_encode, config_handler.get("admin_app", "JWT_SECRET_KEY", "dev-jwt-secret-key"), algorithm=config_handler.get("admin_app", "ALGORITHM", "HS256"))
    return encoded_jwt


def verify_token(token: str) -> Optional[Dict[str, Any]]:
    """验证令牌"""
    try:
        payload = jwt.decode(token, config_handler.get("admin_app", "JWT_SECRET_KEY", "dev-jwt-secret-key"), algorithms=[config_handler.get("admin_app", "ALGORITHM", "HS256")])
        return payload
    except JWTError:
        return None


def generate_random_string(length: int = 32) -> str:
    """生成随机字符串"""
    alphabet = string.ascii_letters + string.digits
    return ''.join(secrets.choice(alphabet) for _ in range(length))


def generate_authorization_code() -> str:
    """生成授权码"""
    return generate_random_string(32)


def generate_app_key() -> str:
    """生成应用Key"""
    return generate_random_string(32)


def generate_app_secret() -> str:
    """生成应用Secret"""
    return generate_random_string(64)


def generate_state() -> str:
    """生成状态码"""
    return generate_random_string(16)


def hash_client_secret(secret: str) -> str:
    """客户端密钥哈希"""
    return hashlib.sha256(secret.encode()).hexdigest()


def verify_client_secret(plain_secret: str, hashed_secret: str) -> bool:
    """验证客户端密钥"""
    return hash_client_secret(plain_secret) == hashed_secret


def encode_basic_auth(username: str, password: str) -> str:
    """编码Basic认证"""
    credentials = f"{username}:{password}"
    encoded_credentials = base64.b64encode(credentials.encode()).decode()
    return f"Basic {encoded_credentials}"


def decode_basic_auth(auth_header: str) -> Optional[tuple[str, str]]:
    """解码Basic认证"""
    try:
        if not auth_header.startswith("Basic "):
            return None
        
        encoded_credentials = auth_header[6:]
        decoded_credentials = base64.b64decode(encoded_credentials).decode()
        username, password = decoded_credentials.split(":", 1)
        return username, password
    except Exception:
        return None


def is_safe_url(url: str, allowed_hosts: list[str]) -> bool:
    """检查URL是否安全"""
    try:
        from urllib.parse import urlparse
        parsed = urlparse(url)
        return parsed.netloc in allowed_hosts
    except Exception:
        return False


def generate_csrf_token() -> str:
    """生成CSRF令牌"""
    return generate_random_string(32)


def mask_sensitive_data(data: str, mask_char: str = "*", visible_chars: int = 4) -> str:
    """掩码敏感数据"""
    if len(data) <= visible_chars:
        return mask_char * len(data)
    
    return data[:visible_chars] + mask_char * (len(data) - visible_chars)