from fastapi import FastAPI, Request, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import structlog
from datetime import datetime, timedelta
from typing import Dict, Any, Optional, List
from pydantic import BaseModel
import secrets

from app.config import get_settings

# 配置日志
structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.stdlib.PositionalArgumentsFormatter(),
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.StackInfoRenderer(),
        structlog.processors.format_exc_info,
        structlog.processors.UnicodeDecoder(),
        structlog.processors.JSONRenderer()
    ],
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
    wrapper_class=structlog.stdlib.BoundLogger,
    cache_logger_on_first_use=True,
)

logger = structlog.get_logger()

# 创建 FastAPI 应用
app = FastAPI(
    title="Gitea Webhook Ambassador (Demo)",
    description="高性能的 Gitea 到 Jenkins 的 Webhook 服务 - 演示版本",
    version="1.0.0"
)

# 添加 CORS 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 安全配置
security = HTTPBearer(auto_error=False)

# 演示数据存储
api_keys = {
    "demo_admin_key": {
        "name": "演示管理员密钥",
        "key_hash": "demo_admin_key",
        "key_prefix": "demo_adm",
        "created_at": datetime.utcnow(),
        "last_used": datetime.utcnow(),
        "is_active": True,
        "role": "admin"
    },
    "demo_user_key": {
        "name": "演示用户密钥",
        "key_hash": "demo_user_key",
        "key_prefix": "demo_usr",
        "created_at": datetime.utcnow(),
        "last_used": datetime.utcnow(),
        "is_active": True,
        "role": "user"
    }
}

trigger_logs = [
    {
        "id": 1,
        "repository_name": "freeleaps/test-project",
        "branch_name": "main",
        "commit_sha": "abc123def456",
        "job_name": "test-project-build",
        "status": "success",
        "error_message": None,
        "created_at": datetime.utcnow() - timedelta(hours=2)
    },
    {
        "id": 2,
        "repository_name": "freeleaps/another-project",
        "branch_name": "dev",
        "commit_sha": "def456ghi789",
        "job_name": "another-project-dev",
        "status": "success",
        "error_message": None,
        "created_at": datetime.utcnow() - timedelta(hours=1)
    },
    {
        "id": 3,
        "repository_name": "freeleaps/test-project",
        "branch_name": "feature/new-feature",
        "commit_sha": "ghi789jkl012",
        "job_name": "test-project-feature",
        "status": "failed",
        "error_message": "Build timeout",
        "created_at": datetime.utcnow() - timedelta(minutes=30)
    }
]

project_mappings = {
    1: {
        "repository_name": "freeleaps/test-project",
        "default_job": "test-project-build",
        "branch_jobs": [
            {"branch": "dev", "job": "test-project-dev"},
            {"branch": "staging", "job": "test-project-staging"}
        ],
        "branch_patterns": [
            {"pattern": "feature/*", "job": "test-project-feature"},
            {"pattern": "hotfix/*", "job": "test-project-hotfix"}
        ],
        "created_at": datetime.utcnow() - timedelta(days=1),
        "updated_at": datetime.utcnow() - timedelta(hours=6)
    }
}

# 请求/响应模型
class HealthResponse(BaseModel):
    status: str
    service: str
    version: str
    timestamp: datetime
    jenkins: Dict[str, Any]
    worker_pool: Dict[str, Any]
    database: Dict[str, Any]

class TriggerLogResponse(BaseModel):
    id: int
    repository_name: str
    branch_name: str
    commit_sha: str
    job_name: str
    status: str
    error_message: Optional[str] = None
    created_at: datetime

class APIKeyResponse(BaseModel):
    id: str
    name: str
    key_prefix: str
    created_at: datetime
    last_used: datetime
    is_active: bool
    role: str

class ProjectMappingResponse(BaseModel):
    id: int
    repository_name: str
    default_job: str
    branch_jobs: List[dict]
    branch_patterns: List[dict]
    created_at: datetime
    updated_at: datetime

# 认证函数
def verify_api_key(api_key: str):
    """验证 API 密钥"""
    for key_id, key_data in api_keys.items():
        if key_data["key_hash"] == api_key and key_data["is_active"]:
            # 更新最后使用时间
            key_data["last_used"] = datetime.utcnow()
            return key_data
    return None

async def get_current_user(
    credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)
):
    """获取当前用户（支持 API 密钥认证）"""
    if not credentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="需要认证令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    token = credentials.credentials
    
    # 验证 API 密钥
    api_key_data = verify_api_key(token)
    if api_key_data:
        return {
            "username": api_key_data["name"],
            "auth_type": "api_key",
            "role": api_key_data["role"]
        }
    
    # 认证失败
    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证令牌",
        headers={"WWW-Authenticate": "Bearer"},
    )

# 公开端点
@app.get("/health", response_model=HealthResponse)
async def health_check():
    """健康检查端点"""
    settings = get_settings()
    
    return HealthResponse(
        status="healthy",
        service="Gitea Webhook Ambassador (Demo)",
        version=settings.version,
        timestamp=datetime.utcnow(),
        jenkins={"status": "connected"},
        worker_pool={
            "active_workers": 2,
            "queue_size": 0,
            "total_processed": len(trigger_logs),
            "total_failed": len([log for log in trigger_logs if log["status"] == "failed"])
        },
        database={"status": "connected"}
    )

@app.get("/")
async def root():
    """根路径"""
    return {
        "name": "Gitea Webhook Ambassador (Demo)",
        "version": "1.0.0",
        "description": "高性能的 Gitea 到 Jenkins 的 Webhook 服务 - 演示版本",
        "endpoints": {
            "webhook": "/webhook/gitea",
            "health": "/health",
            "logs": "/api/logs",
            "admin": "/api/admin"
        },
        "demo_keys": {
            "admin": "demo_admin_key",
            "user": "demo_user_key"
        }
    }

@app.post("/webhook/gitea")
async def handle_gitea_webhook(request: Request):
    """处理 Gitea webhook 请求"""
    try:
        body = await request.body()
        
        # 记录 webhook 请求
        logger.info("Received Gitea webhook", 
                   body_size=len(body),
                   headers=dict(request.headers))
        
        # 添加新的触发日志
        log_entry = {
            "id": len(trigger_logs) + 1,
            "repository_name": "demo-repo",
            "branch_name": "main",
            "commit_sha": "demo123",
            "job_name": "demo-job",
            "status": "success",
            "error_message": None,
            "created_at": datetime.utcnow()
        }
        trigger_logs.append(log_entry)
        
        return {
            "success": True,
            "message": "Webhook received successfully",
            "data": {
                "body_size": len(body),
                "timestamp": datetime.utcnow().isoformat()
            }
        }
        
    except Exception as e:
        logger.error("Webhook processing failed", error=str(e))
        return JSONResponse(
            status_code=500,
            content={
                "success": False,
                "message": "Webhook processing failed",
                "error": str(e)
            }
        )

# 需要认证的端点
@app.get("/api/logs", response_model=List[TriggerLogResponse])
async def get_trigger_logs(
    repository: Optional[str] = None,
    branch: Optional[str] = None,
    limit: int = 100,
    current_user: dict = Depends(get_current_user)
):
    """获取触发日志"""
    print(f"用户 {current_user['username']} 访问日志端点")
    
    filtered_logs = trigger_logs.copy()
    
    if repository:
        filtered_logs = [log for log in filtered_logs if log["repository_name"] == repository]
    if branch:
        filtered_logs = [log for log in filtered_logs if log["branch_name"] == branch]
    
    # 按时间倒序排列并限制数量
    filtered_logs.sort(key=lambda x: x["created_at"], reverse=True)
    return filtered_logs[:limit]

@app.get("/api/logs/stats")
async def get_log_stats(current_user: dict = Depends(get_current_user)):
    """获取日志统计信息"""
    print(f"用户 {current_user['username']} 访问日志统计")
    
    total_logs = len(trigger_logs)
    successful_logs = len([log for log in trigger_logs if log["status"] == "success"])
    failed_logs = len([log for log in trigger_logs if log["status"] == "failed"])
    
    # 最近24小时的日志数
    yesterday = datetime.utcnow() - timedelta(days=1)
    recent_logs = len([log for log in trigger_logs if log["created_at"] >= yesterday])
    
    # 按仓库分组的统计
    repo_stats = {}
    for log in trigger_logs:
        repo = log["repository_name"]
        repo_stats[repo] = repo_stats.get(repo, 0) + 1
    
    return {
        "total_logs": total_logs,
        "successful_logs": successful_logs,
        "failed_logs": failed_logs,
        "recent_logs_24h": recent_logs,
        "repository_stats": [
            {"repository": repo, "count": count} 
            for repo, count in repo_stats.items()
        ]
    }

@app.get("/api/admin/api-keys", response_model=List[APIKeyResponse])
async def list_api_keys(current_user: dict = Depends(get_current_user)):
    """列出所有 API 密钥（仅管理员）"""
    if current_user["role"] != "admin":
        raise HTTPException(status_code=403, detail="需要管理员权限")
    
    print(f"管理员 {current_user['username']} 查看 API 密钥列表")
    
    return [
        APIKeyResponse(
            id=key_id,
            name=key_data["name"],
            key_prefix=key_data["key_prefix"],
            created_at=key_data["created_at"],
            last_used=key_data["last_used"],
            is_active=key_data["is_active"],
            role=key_data["role"]
        )
        for key_id, key_data in api_keys.items()
    ]

@app.get("/api/admin/projects", response_model=List[ProjectMappingResponse])
async def list_project_mappings(current_user: dict = Depends(get_current_user)):
    """列出所有项目映射"""
    print(f"用户 {current_user['username']} 查看项目映射")
    
    return [
        ProjectMappingResponse(
            id=mapping_id,
            repository_name=mapping_data["repository_name"],
            default_job=mapping_data["default_job"],
            branch_jobs=mapping_data["branch_jobs"],
            branch_patterns=mapping_data["branch_patterns"],
            created_at=mapping_data["created_at"],
            updated_at=mapping_data["updated_at"]
        )
        for mapping_id, mapping_data in project_mappings.items()
    ]

@app.get("/api/admin/stats")
async def get_admin_stats(current_user: dict = Depends(get_current_user)):
    """获取管理统计信息"""
    print(f"用户 {current_user['username']} 查看管理统计")
    
    total_keys = len(api_keys)
    active_keys = len([key for key in api_keys.values() if key["is_active"]])
    
    # 最近使用的密钥
    week_ago = datetime.utcnow() - timedelta(days=7)
    recent_keys = len([
        key for key in api_keys.values() 
        if key["last_used"] >= week_ago
    ])
    
    total_mappings = len(project_mappings)
    
    return {
        "api_keys": {
            "total": total_keys,
            "active": active_keys,
            "recently_used": recent_keys
        },
        "project_mappings": {
            "total": total_mappings
        }
    }

# 中间件
@app.middleware("http")
async def log_requests(request: Request, call_next):
    """请求日志中间件"""
    start_time = datetime.utcnow()
    
    response = await call_next(request)
    
    process_time = (datetime.utcnow() - start_time).total_seconds()
    response.headers["X-Process-Time"] = str(process_time)
    
    return response

if __name__ == "__main__":
    import uvicorn
    settings = get_settings()
    
    print("🚀 启动 Gitea Webhook Ambassador 演示版本")
    print("=" * 60)
    print("📋 演示 API 密钥:")
    print("   管理员密钥: demo_admin_key")
    print("   用户密钥: demo_user_key")
    print()
    print("🔧 使用示例:")
    print("   curl -H 'Authorization: Bearer demo_admin_key' http://localhost:8000/api/admin/api-keys")
    print("   curl -H 'Authorization: Bearer demo_user_key' http://localhost:8000/api/logs")
    print("=" * 60)
    
    uvicorn.run(
        "app.main_demo:app",
        host=settings.server.host,
        port=settings.server.port,
        reload=settings.server.reload
    ) 