# FastAPI 相关导入
from fastapi import FastAPI, HTTPException, status, UploadFile, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, FileResponse, Response
from fastapi.staticfiles import StaticFiles

# 数据模型和验证相关
from pydantic import BaseModel
from typing import Optional, List

# 数据库相关
from sqlalchemy import select, func, delete, desc
from database import get_session, AccountModel, AccountUsageRecordModel, init_db

# 文件和路径处理
from pathlib import Path

# 时间处理
from datetime import datetime

# 异步和上下文管理
import asyncio
from contextlib import asynccontextmanager

# 系统和环境相关
import os
import traceback
import uvicorn
from dotenv import load_dotenv

# 日志和错误处理
from logger import info, error

# 自定义模块
from cursor_pro_keep_alive import main as register_account
from tokenManager.cursor import Cursor

# 并发和缓存
import concurrent.futures
from functools import lru_cache

# 配置参数
from config import (
    MAX_ACCOUNTS,
    REGISTRATION_INTERVAL,
    API_HOST,
    API_PORT,
    API_DEBUG,
    API_WORKERS,
)

# 其他工具
import json
import time

# 全局状态追踪
registration_status = {
    "is_running": False,
    "last_run": None,
    "last_status": None,
    "next_run": None,
    "total_runs": 0,
    "successful_runs": 0,
    "failed_runs": 0,
}

# 定义静态文件目录
static_path = Path(__file__).parent / "static"
static_path.mkdir(exist_ok=True)  # 确保目录存在

# 全局任务存储
background_tasks = {"registration_task": None}


# 添加lifespan管理器，在应用启动时初始化数据库
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动时初始化数据库
    await init_db()
    info(f'服务已启动! \n 首页地址：http://127.0.0.1:{API_PORT}/')
    yield
    # 关闭时的清理操作
    info("应用程序已关闭!")


app = FastAPI(
    title="Cursor Account API",
    description="API for managing Cursor accounts",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
    lifespan=lifespan,
    debug=API_DEBUG,
)


# 挂载静态文件目录
app.mount("/static", StaticFiles(directory=str(static_path)), name="static")

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

class Account(BaseModel):
    email: str
    password: Optional[str] = None
    token: str
    user: str
    usage_limit: Optional[str] = None
    created_at: Optional[str] = None
    status: str = "active"  # 默认为"active"
    id: Optional[int] = None  # 添加id字段，可选

    class Config:
        from_attributes = True


class AccountResponse(BaseModel):
    success: bool
    data: Optional[Account] = None
    message: str = ""


async def get_active_account_count() -> int:
    """获取当前账号总数"""
    async with get_session() as session:
        result = await session.execute(
            select(func.count())
            .select_from(AccountModel)
            .where(AccountModel.status == "active")
        )
        return result.scalar()


async def get_account_count() -> int:
    """获取当前账号总数"""
    async with get_session() as session:
        result = await session.execute(select(func.count()).select_from(AccountModel))
        return result.scalar()


async def run_registration():
    """运行注册脚本"""
    global registration_status
    browser_manager = None

    try:
        info("注册任务开始运行")

        while registration_status["is_running"]:
            try:
                count = await get_active_account_count()
                info(f"当前数据库已激活账号数: {count}")

                if count >= MAX_ACCOUNTS:
                    # 修改：不再结束任务，而是进入监控模式
                    info(f"已达到最大账号数量 ({count}/{MAX_ACCOUNTS})，进入监控模式")
                    registration_status["last_status"] = "monitoring"

                    # 等待检测间隔时间
                    next_check = datetime.now().timestamp() + REGISTRATION_INTERVAL
                    registration_status["next_run"] = next_check
                    info(f"将在 {REGISTRATION_INTERVAL} 秒后重新检查账号数量")
                    await asyncio.sleep(REGISTRATION_INTERVAL)

                    # 跳过当前循环的剩余部分，继续下一次循环检查
                    continue

                info(f"开始注册尝试 (当前账号数: {count}/{MAX_ACCOUNTS})")
                registration_status["last_run"] = datetime.now().isoformat()
                registration_status["total_runs"] += 1

                # 调用注册函数
                try:
                    success = await asyncio.get_event_loop().run_in_executor(
                        None, register_account
                    )

                    if success:
                        registration_status["successful_runs"] += 1
                        registration_status["last_status"] = "success"
                        info("注册成功")
                    else:
                        registration_status["failed_runs"] += 1
                        registration_status["last_status"] = "failed"
                        info("注册失败")
                except SystemExit:
                    # 捕获 SystemExit 异常，这是注册脚本正常退出的方式
                    info("注册脚本正常退出")
                    if registration_status["last_status"] != "error":
                        registration_status["last_status"] = "completed"
                except Exception as e:
                    error(f"注册过程执行出错: {str(e)}")
                    error(traceback.format_exc())
                    registration_status["failed_runs"] += 1
                    registration_status["last_status"] = "error"

                # 更新下次运行时间
                next_run = datetime.now().timestamp() + REGISTRATION_INTERVAL
                registration_status["next_run"] = next_run

                info(f"等待 {REGISTRATION_INTERVAL} 秒后进行下一次尝试")
                await asyncio.sleep(REGISTRATION_INTERVAL)

            except asyncio.CancelledError:
                info("注册迭代被取消")
                raise
            except Exception as e:
                registration_status["failed_runs"] += 1
                registration_status["last_status"] = "error"
                error(f"注册过程出错: {str(e)}")
                error(traceback.format_exc())
                if not registration_status["is_running"]:
                    break
                await asyncio.sleep(REGISTRATION_INTERVAL)
    except asyncio.CancelledError:
        info("注册任务被取消")
        raise
    except Exception as e:
        error(f"注册任务致命错误: {str(e)}")
        error(traceback.format_exc())
        raise
    finally:
        registration_status["is_running"] = False
        if browser_manager:
            try:
                browser_manager.quit()
            except Exception as e:
                error(f"清理浏览器资源时出错: {str(e)}")
                error(traceback.format_exc())


@app.get("/", tags=["UI"])
async def serve_index():
    """提供Web UI界面"""
    index_path = Path(__file__).parent / "index.html"
    return FileResponse(index_path)


@app.get("/general", tags=["General"])
async def root():
    """API根路径，返回API信息"""
    try:
        # 获取当前账号数量和使用情况
        async with get_session() as session:
            result = await session.execute(select(AccountModel))
            accounts = result.scalars().all()

            usage_info = []
            total_balance = 0
            active_accounts = 0

            for acc in accounts:
                remaining_balance = Cursor.get_remaining_balance(acc.user, acc.token)
                remaining_days = Cursor.get_trial_remaining_days(acc.user, acc.token)

                if remaining_balance is not None and remaining_balance > 0:
                    active_accounts += 1
                    total_balance += remaining_balance

                usage_info.append(
                    {
                        "email": acc.email,
                        "balance": remaining_balance,
                        "days": remaining_days,
                        "status": (
                            "active"
                            if remaining_balance is not None and remaining_balance > 0
                            else "inactive"
                        ),
                    }
                )

        return {
            "service": {
                "name": "Cursor Account API",
                "version": "1.0.0",
                "status": "running",
                "description": "API for managing Cursor Pro accounts and automatic registration",
            },
            "statistics": {
                "total_accounts": len(accounts),
                "active_accounts": active_accounts,
                "total_remaining_balance": total_balance,
                "max_accounts": MAX_ACCOUNTS,
                "remaining_slots": MAX_ACCOUNTS - len(accounts),
                "registration_interval": f"{REGISTRATION_INTERVAL} seconds",
            },
            "accounts_info": usage_info,  # 添加账号详细信息
            "registration_status": {
                "is_running": registration_status["is_running"],
                "last_run": registration_status["last_run"],
                "last_status": registration_status["last_status"],
                "next_run": registration_status["next_run"],
                "statistics": {
                    "total_runs": registration_status["total_runs"],
                    "successful_runs": registration_status["successful_runs"],
                    "failed_runs": registration_status["failed_runs"],
                    "success_rate": (
                        f"{(registration_status['successful_runs'] / registration_status['total_runs'] * 100):.1f}%"
                        if registration_status["total_runs"] > 0
                        else "N/A"
                    ),
                },
            },
            "endpoints": {
                "documentation": {"swagger": "/docs", "redoc": "/redoc"},
                "health": {
                    "check": "/health",
                    "registration_status": "/registration/status",
                },
                "accounts": {
                    "list_all": "/accounts",
                    "random": "/account/random",
                    "create": {"path": "/account", "method": "POST"},
                    "delete": {"path": "/account/{email}", "method": "DELETE"},
                    "usage": {
                        "path": "/account/{email}/usage",
                        "method": "GET",
                        "description": "Get account usage by email",
                    },
                },
                "registration": {
                    "start": {"path": "/registration/start", "method": "GET"},
                    "stop": {"path": "/registration/stop", "method": "POST"},
                    "status": {"path": "/registration/status", "method": "GET"},
                },
                "usage": {"check": {"path": "/usage", "method": "GET"}},
                "clean": {
                    "run": {
                        "path": "/clean",
                        "method": "POST",
                        "params": {"clean_type": ["check", "disable", "delete"]},
                    }
                },
            },
            "support": {
                "github": "https://github.com/Elawen-Carl/cursor-account-api",
                "author": "Elawen Carl",
                "contact": "elawencarl@gmail.com",
            },
            "timestamp": datetime.now().isoformat(),
        }
    except Exception as e:
        error(f"根端点错误: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Error fetching API information",
        )


@app.get("/health", tags=["General"])
async def health_check():
    """健康检查端点"""
    return {"status": "healthy"}


@app.get("/accounts", tags=["Accounts"])
async def get_accounts(
    page: int = 1, 
    per_page: int = 10, 
    search: Optional[str] = None,
    sort_by: str = "created_at",  # 新增排序字段参数
    order: str = "desc"  # 新增排序方向参数
):
    """获取所有账号列表，支持分页、搜索和排序"""
    try:
        async with get_session() as session:
            # 验证排序参数
            valid_sort_fields = {"id", "email", "created_at", "usage_limit"}
            valid_orders = {"asc", "desc"}
            
            if sort_by not in valid_sort_fields:
                sort_by = "created_at"  # 默认排序字段
            if order not in valid_orders:
                order = "desc"  # 默认排序方向
            
            # 构建基本查询
            query = select(AccountModel)
            
            # 应用排序
            sort_field = getattr(AccountModel, sort_by)
            if order == "desc":
                query = query.order_by(desc(sort_field))
            else:
                query = query.order_by(sort_field)
                
            # 如果有搜索参数
            if search:
                search = f"%{search}%"
                query = query.where(AccountModel.email.like(search))
            
            # 计算总记录数
            count_query = select(func.count()).select_from(AccountModel)
            if search:
                count_query = count_query.where(AccountModel.email.like(search))
            total_count = await session.scalar(count_query)
            
            # 计算分页
            total_pages = (total_count + per_page - 1) // per_page  # 向上取整
            
            # 应用分页
            query = query.offset((page - 1) * per_page).limit(per_page)
            
            # 执行查询
            result = await session.execute(query)
            accounts = result.scalars().all()
            
            # 构建分页响应
            return {
                "success": True,
                "data": accounts,
                "pagination": {
                    "page": page,
                    "per_page": per_page,
                    "total_count": total_count,
                    "total_pages": total_pages
                },
                "sort": {
                    "field": sort_by,
                    "order": order
                }
            }
    except Exception as e:
        error(f"获取账号列表失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"获取账号列表失败: {str(e)}",
        )


@app.get("/account/random", response_model=AccountResponse, tags=["Accounts"])
async def get_random_account():
    """随机获取一个可用的账号和token"""
    try:
        async with get_session() as session:
            result = await session.execute(
                select(AccountModel).order_by(func.random()).limit(1)
            )
            account = result.scalar_one_or_none()

            if not account:
                return AccountResponse(success=False, message="No accounts available")

            return AccountResponse(success=True, data=Account.from_orm(account))
    except Exception as e:
        error(f"获取随机账号失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="Internal server error")


@app.post("/account", response_model=AccountResponse, tags=["Accounts"])
async def create_account(account: Account):
    """创建新账号"""
    try:
        async with get_session() as session:
            db_account = AccountModel(
                email=account.email,
                password=account.password,
                token=account.token,
                usage_limit=account.usage_limit,
                created_at=account.created_at,
            )
            session.add(db_account)
            await session.commit()
            return AccountResponse(
                success=True, data=account, message="Account created successfully"
            )
    except Exception as e:
        error(f"创建账号失败: {str(e)}")
        error(traceback.format_exc())
        return AccountResponse(
            success=False, message=f"Failed to create account: {str(e)}"
        )


@app.delete("/account/{email}", response_model=AccountResponse, tags=["Accounts"])
async def delete_account(email: str, hard_delete: bool = False):
    """删除或停用指定邮箱的账号

    如果 hard_delete=True，则物理删除账号
    否则仅将状态设置为'deleted'
    """
    try:
        async with get_session() as session:
            # 先检查账号是否存在
            result = await session.execute(
                select(AccountModel).where(AccountModel.email == email)
            )
            account = result.scalar_one_or_none()

            if not account:
                return AccountResponse(success=False, message=f"账号 {email} 不存在")

            if hard_delete:
                # 物理删除账号
                await session.execute(
                    delete(AccountModel).where(AccountModel.email == email)
                )
                delete_message = f"账号 {email} 已永久删除"
            else:
                # 逻辑删除：将状态更新为'deleted'
                account.status = "deleted"
                delete_message = f"账号 {email} 已标记为删除状态"

            await session.commit()

            return AccountResponse(success=True, message=delete_message)
    except Exception as e:
        error(f"删除账号失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"删除账号失败: {str(e)}",
        )


# 添加状态更新的请求体模型
class StatusUpdate(BaseModel):
    status: str


@app.put("/account/id/{id}/status", response_model=AccountResponse, tags=["Accounts"])
async def update_account_status(id: str, update: StatusUpdate):
    """更新账号状态

    可选状态: active (正常), disabled (停用), deleted (已删除)
    """
    # 使用update.status替代原先的status参数
    try:
        # 验证状态值
        valid_statuses = ["active", "disabled", "deleted"]
        if update.status not in valid_statuses:
            return AccountResponse(
                success=False,
                message=f"无效的状态值。允许的值: {', '.join(valid_statuses)}",
            )

        async with get_session() as session:
            # 通过邮箱查询账号
            result = await session.execute(
                select(AccountModel).where(AccountModel.id == id)
            )
            account = result.scalar_one_or_none()

            if not account:
                return AccountResponse(
                    success=False, message=f"邮箱为 {email} 的账号不存在"
                )

            # 更新状态
            account.status = update.status
            await session.commit()

            return AccountResponse(
                success=True,
                message=f"账号 {account.email} 状态已更新为 '{update.status}'",
            )
    except Exception as e:
        error(f"通过邮箱更新账号状态失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"更新账号状态失败: {str(e)}",
        )


@app.get("/registration/start", tags=["Registration"])
async def start_registration():
    """手动启动注册任务"""
    info("手动启动注册任务")
    global background_tasks, registration_status
    try:
        # 检查是否已达到最大账号数
        count = await get_active_account_count()

        # 检查任务是否已在运行
        if (
            background_tasks["registration_task"]
            and not background_tasks["registration_task"].done()
        ):
            # 确定当前状态
            current_status = (
                "monitoring"
                if registration_status["last_status"] == "monitoring"
                else "running"
            )

            status_message = (
                f"注册任务已在运行中 (状态: {current_status})"
                if current_status == "running"
                else f"已达到最大账号数量({count}/{MAX_ACCOUNTS})，正在监控账号状态，当账号数量减少时将自动继续注册"
            )

            info(f"注册请求被忽略 - 任务已在{current_status}状态")
            return {
                "success": True,
                "message": status_message,
                "status": {
                    "is_running": registration_status["is_running"],
                    "last_run": registration_status["last_run"],
                    "next_run": (
                        datetime.fromtimestamp(
                            registration_status["next_run"]
                        ).isoformat()
                        if registration_status["next_run"]
                        else None
                    ),
                    "last_status": registration_status["last_status"],
                    "current_count": count,
                    "max_accounts": MAX_ACCOUNTS,
                },
            }

        # 重置注册状态
        registration_status.update(
            {
                "is_running": True,
                "last_status": "starting",
                "last_run": datetime.now().isoformat(),
                "next_run": datetime.now().timestamp() + REGISTRATION_INTERVAL,
                "total_runs": 0,
                "successful_runs": 0,
                "failed_runs": 0,
            }
        )

        # 创建并启动新任务
        loop = asyncio.get_running_loop()
        task = loop.create_task(run_registration())
        background_tasks["registration_task"] = task

        # 添加任务完成回调
        def task_done_callback(task):
            try:
                task.result()  # 这将重新引发任何未处理的异常
            except asyncio.CancelledError:
                info("注册任务被取消")
                registration_status["last_status"] = "cancelled"
            except Exception as e:
                error(f"注册任务失败: {str(e)}")
                error(traceback.format_exc())
                registration_status["last_status"] = "error"
            finally:
                if registration_status["is_running"]:  # 只有在任务仍在运行时才更新状态
                    registration_status["is_running"] = False
                background_tasks["registration_task"] = None

        task.add_done_callback(task_done_callback)
        info("手动启动注册任务")

        # 等待任务实际开始运行
        await asyncio.sleep(1)

        # 检查任务是否成功启动
        if task.done():
            try:
                task.result()  # 如果任务已完成，检查是否有异常
            except Exception as e:
                error(f"注册任务启动失败: {str(e)}")
                error(traceback.format_exc())
                registration_status["is_running"] = False
                registration_status["last_status"] = "error"
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail=f"Failed to start registration task: {str(e)}",
                )

        # 检查是否已达到最大账号数，预先设置为监控模式
        if count >= MAX_ACCOUNTS:
            registration_status["last_status"] = "monitoring"
            status_message = f"已达到最大账号数量({count}/{MAX_ACCOUNTS})，进入监控模式，当账号数量减少时将自动继续注册"
        else:
            status_message = "注册任务启动成功"

        return {
            "success": True,
            "message": status_message,
            "status": {
                "is_running": registration_status["is_running"],
                "last_run": registration_status["last_run"],
                "next_run": datetime.fromtimestamp(
                    registration_status["next_run"]
                ).isoformat(),
                "last_status": registration_status["last_status"],
                "current_count": count,
                "max_accounts": MAX_ACCOUNTS,
            },
        }
    except Exception as e:
        error(f"启动注册任务失败: {str(e)}")
        error(traceback.format_exc())
        registration_status["is_running"] = False
        registration_status["last_status"] = "error"
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to start registration task: {str(e)}",
        )


@app.get("/registration/stop", tags=["Registration"])
async def stop_registration():
    """手动停止注册任务"""
    global background_tasks
    try:
        if (
            not background_tasks["registration_task"]
            or background_tasks["registration_task"].done()
        ):
            return {"success": False, "message": "No running registration task found"}

        background_tasks["registration_task"].cancel()
        try:
            await background_tasks["registration_task"]
        except asyncio.CancelledError:
            info("注册任务被取消")

        background_tasks["registration_task"] = None
        registration_status["is_running"] = False
        registration_status["last_status"] = "manually stopped"

        return {"success": True, "message": "Registration task stopped successfully"}
    except Exception as e:
        error(f"停止注册任务失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to stop registration task: {str(e)}",
        )


@app.get("/registration/status", tags=["Registration"])
async def get_registration_status():
    """获取注册状态"""
    try:
        count = await get_account_count()
        active_count = await get_active_account_count()  # 添加获取活跃账号数

        # 更新任务状态逻辑
        if (
            background_tasks["registration_task"]
            and not background_tasks["registration_task"].done()
        ):
            if registration_status["last_status"] == "monitoring":
                task_status = "monitoring"  # 新增监控状态
            else:
                task_status = "running"
        else:
            task_status = "stopped"

        status_info = {
            "current_count": count,
            "active_count": active_count,  # 添加活跃账号数
            "max_accounts": MAX_ACCOUNTS,
            "is_registration_active": active_count < MAX_ACCOUNTS,
            "remaining_slots": MAX_ACCOUNTS - active_count,
            "task_status": task_status,
            "registration_details": {
                "is_running": registration_status["is_running"],
                "last_run": registration_status["last_run"],
                "last_status": registration_status["last_status"],
                "next_run": registration_status["next_run"],
                "statistics": {
                    "total_runs": registration_status["total_runs"],
                    "successful_runs": registration_status["successful_runs"],
                    "failed_runs": registration_status["failed_runs"],
                    "success_rate": (
                        f"{(registration_status['successful_runs'] / registration_status['total_runs'] * 100):.1f}%"
                        if registration_status["total_runs"] > 0
                        else "N/A"
                    ),
                },
            },
        }

        # 添加状态解释信息
        if task_status == "monitoring":
            status_info["status_message"] = (
                f"已达到最大账号数量({active_count}/{MAX_ACCOUNTS})，正在监控账号状态，当账号数量减少时将自动继续注册"
            )
        elif task_status == "running":
            status_info["status_message"] = (
                f"正在执行注册流程，当前账号数：{active_count}/{MAX_ACCOUNTS}"
            )
        else:
            status_info["status_message"] = "注册任务未运行"

        # info(f"请求注册状态 (当前账号数: {count}, 活跃账号数: {active_count}, 状态: {task_status})")
        return status_info

    except Exception as e:
        error(f"获取注册状态失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Failed to get registration status: {str(e)}",
        )


# 自定义异常处理
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
    error(f"HTTP错误发生: {exc.detail}")
    return JSONResponse(
        status_code=exc.status_code, content={"success": False, "message": exc.detail}
    )


@app.exception_handler(Exception)
async def general_exception_handler(request, exc):
    error(f"意外错误发生: {str(exc)}")
    error(f"错误详情: {traceback.format_exc()}")
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content={
            "success": False,
            "message": "Internal server error occurred",
            "detail": str(exc) if app.debug else None,
        },
    )


# 添加缓存装饰器
@lru_cache(maxsize=100)
def get_account_status(user: str, token: str, timestamp: int):
    """缓存10分钟内的账号状态"""
    balance = Cursor.get_remaining_balance(user, token)
    days = Cursor.get_trial_remaining_days(user, token)
    return {
        "balance": balance,
        "days": days,
        "status": "active" if balance is not None and balance > 0 else "inactive",
    }


# 修改 check_usage 接口
@app.get("/usage")
async def check_usage():
    """
    获取所有账号的使用量信息
    
    该接口会并发查询所有账号的余额和剩余天数，并返回汇总信息
    使用了缓存机制避免频繁请求API，缓存时间为10分钟
    
    返回:
        - total_accounts: 总账号数量
        - usage_info: 每个账号的详细使用量信息列表
        - summary: 账号状态汇总信息，包括活跃账号数、非活跃账号数和总剩余额度
    """
    try:
        async with get_session() as session:
            # 从数据库获取所有账号
            result = await session.execute(select(AccountModel))
            accounts = result.scalars().all()

            # 使用当前时间的10分钟间隔作为缓存key
            # 将时间戳除以600(10分钟)取整，作为缓存标识
            cache_timestamp = int(datetime.now().timestamp() / 600)

            # 使用线程池并发获取账号状态，最多10个并发线程
            # 避免串行请求API导致接口响应过慢
            with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
                # 为每个账号创建一个异步任务
                futures = [
                    executor.submit(
                        get_account_status, acc.user, acc.token, cache_timestamp
                    )
                    for acc in accounts
                ]

                # 收集每个账号的使用量信息
                usage_info = []
                for acc, future in zip(accounts, futures):
                    status = future.result()
                    usage_info.append(
                        {
                            "email": acc.email,
                            "usage_limit": status["balance"],  # 剩余额度
                            "remaining_days": status["days"],  # 剩余天数
                            "status": status["status"],        # 账号状态
                        }
                    )

            # 返回汇总信息
            return {
                "total_accounts": len(accounts),  # 总账号数
                "usage_info": usage_info,         # 详细使用量信息
                "summary": {
                    # 统计活跃账号数量
                    "active_accounts": sum(
                        1 for info in usage_info if info["status"] == "active"
                    ),
                    # 统计非活跃账号数量
                    "inactive_accounts": sum(
                        1 for info in usage_info if info["status"] == "inactive"
                    ),
                    # 计算所有账号的总剩余额度
                    "total_remaining_balance": sum(
                        info["usage_limit"] or 0 for info in usage_info
                    ),
                },
            }
    except Exception as e:
        # 记录错误日志
        error(f"检查使用量失败: {str(e)}")
        error(traceback.format_exc())
        # 抛出HTTP异常
        raise HTTPException(status_code=500, detail=str(e))


@app.get("/account/{email}/usage", tags=["Accounts"])
async def get_account_usage(email: str):
    """根据邮箱查询账户使用量并更新数据库"""
    try:
        async with get_session() as session:
            # 查询指定邮箱的账号
            result = await session.execute(
                select(AccountModel).where(AccountModel.email == email)
            )
            account = result.scalar_one_or_none()

            if not account:
                raise HTTPException(
                    status_code=404, detail=f"Account with email {email} not found"
                )

            # 获取账号使用量
            remaining_balance = Cursor.get_remaining_balance(
                account.user, account.token
            )
            remaining_days = Cursor.get_trial_remaining_days(
                account.user, account.token
            )

            # 计算总额度和已使用额度
            total_limit = 150  # 默认总额度
            used_limit = 0

            if remaining_balance is not None:
                used_limit = total_limit - remaining_balance
                if remaining_days is not None and remaining_days == 0:
                    account.status = "disabled"

                # 更新数据库中的usage_limit字段
                account.usage_limit = str(remaining_balance)
                await session.commit()
                db_updated = True
            else:
                db_updated = False

            return {
                "success": True,
                "email": account.email,
                "usage": {
                    "remaining_balance": remaining_balance,
                    "total_limit": total_limit,
                    "used_limit": used_limit,
                    "remaining_days": remaining_days,
                    "status": (
                        "active"
                        if remaining_balance is not None and remaining_balance > 0
                        else "inactive"
                    ),
                },
                "db_updated": db_updated,
                "timestamp": datetime.now().isoformat(),
            }

    except HTTPException:
        raise
    except Exception as e:
        error(f"查询账号使用量失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"Failed to get account usage: {str(e)}"}


# 添加通过ID删除账号的API
@app.delete("/account/id/{id}", response_model=AccountResponse, tags=["Accounts"])
async def delete_account_by_id(id: int, hard_delete: bool = False):
    """通过ID删除或停用账号

    如果 hard_delete=True，则物理删除账号
    否则仅将状态设置为'deleted'
    """
    try:
        async with get_session() as session:
            # 通过ID查询账号
            result = await session.execute(
                select(AccountModel).where(AccountModel.id == id)
            )
            account = result.scalar_one_or_none()

            if not account:
                return AccountResponse(success=False, message=f"ID为 {id} 的账号不存在")

            email = account.email  # 保存邮箱以在响应中显示

            if hard_delete:
                # 物理删除账号
                await session.execute(delete(AccountModel).where(AccountModel.id == id))
                delete_message = f"账号 {email} (ID: {id}) 已永久删除"
            else:
                # 逻辑删除：将状态更新为'deleted'
                account.status = "deleted"
                delete_message = f"账号 {email} (ID: {id}) 已标记为删除状态"

            await session.commit()

            return AccountResponse(success=True, message=delete_message)
    except Exception as e:
        error(f"通过ID删除账号失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"删除账号失败: {str(e)}",
        )

# 添加导出账号列表功能
@app.get("/accounts/export", tags=["Accounts"])
async def export_accounts():
    """导出所有账号为JSON文件"""
    try:
        async with get_session() as session:
            query = select(AccountModel).order_by(desc(AccountModel.created_at))
            result = await session.execute(query)
            accounts = result.scalars().all()
            
            # 转换为可序列化的数据
            accounts_data = []
            for account in accounts:
                account_dict = {
                    "id": account.id,
                    "email": account.email,
                    "password": account.password,
                    "token": account.token,
                    "user": account.user,
                    "usage_limit": account.usage_limit,
                    "created_at": account.created_at,
                    "status": account.status
                }
                accounts_data.append(account_dict)
            
            # 创建响应
            content = json.dumps(accounts_data, ensure_ascii=False, indent=2)
            response = Response(content=content)
            response.headers["Content-Disposition"] = "attachment; filename=cursor_accounts.json"
            response.headers["Content-Type"] = "application/json"
            
            return response
            
    except Exception as e:
        error(f"导出账号失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"导出账号失败: {str(e)}",
        )

# 添加导入账号列表功能
@app.post("/accounts/import", tags=["Accounts"])
async def import_accounts(file: UploadFile):
    """从JSON文件导入账号"""
    try:
        # 读取上传的文件内容
        content = await file.read()
        
        # 解析JSON数据
        try:
            accounts_data = json.loads(content.decode("utf-8"))
        except json.JSONDecodeError:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="无效的JSON文件格式",
            )
        
        # 验证数据结构
        if not isinstance(accounts_data, list):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="JSON数据必须是账号对象的数组",
            )
            
        # 导入计数器
        imported = 0
        updated = 0
        skipped = 0
        
        async with get_session() as session:
            for account_data in accounts_data:
                # 提取必要字段，提供默认值
                email = account_data.get("email")
                if not email:
                    skipped += 1
                    continue
                    
                # 检查账号是否已存在
                query = select(AccountModel).where(AccountModel.email == email)
                result = await session.execute(query)
                existing_account = result.scalar_one_or_none()
                
                if existing_account:
                    # 更新现有账号
                    existing_account.password = account_data.get("password", existing_account.password)
                    existing_account.token = account_data.get("token", existing_account.token)
                    existing_account.user = account_data.get("user", existing_account.user)
                    existing_account.usage_limit = account_data.get("usage_limit", existing_account.usage_limit)
                    existing_account.status = account_data.get("status", existing_account.status)
                    updated += 1
                else:
                    # 创建新账号
                    new_account = AccountModel(
                        id=account_data.get("id", int(time.time() * 1000)),
                        email=email,
                        password=account_data.get("password", ""),
                        token=account_data.get("token", ""),
                        user=account_data.get("user", ""),
                        usage_limit=account_data.get("usage_limit", ""),
                        created_at=account_data.get("created_at", datetime.now().strftime("%Y-%m-%d %H:%M")),
                        status=account_data.get("status", "active")
                    )
                    session.add(new_account)
                    imported += 1
                    
            # 提交所有更改
            await session.commit()
            
        return {
            "success": True,
            "message": f"导入完成: 新增 {imported} 个账号, 更新 {updated} 个账号, 跳过 {skipped} 个无效记录",
        }
            
    except HTTPException:
        raise
    except Exception as e:
        error(f"导入账号失败: {str(e)}")
        error(traceback.format_exc())
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"导入账号失败: {str(e)}",
        )

# 添加"使用Token"功能
@app.post("/account/use-token/{id}", tags=["Accounts"])
async def use_account_token(id: int, request: Request, reset_machine_id: bool = False):
    """使用指定账号的Token更新Cursor认证，可选是否重置机器ID"""
    try:
        async with get_session() as session:
            # 通过ID查询账号
            result = await session.execute(
                select(AccountModel).where(AccountModel.id == id)
            )
            account = result.scalar_one_or_none()

            if not account:
                return {"success": False, "message": f"ID为 {id} 的账号不存在"}

            # 调用CursorAuthManager更新认证
            from cursor_auth_manager import CursorAuthManager

            auth_manager = CursorAuthManager()
            success = auth_manager.update_auth(
                email=account.email,
                access_token=account.token,
                refresh_token=account.token
            )
            
            # 仅在用户选择时才重置机器ID
            patch_success = False
            if reset_machine_id:
                from cursor_shadow_patcher import CursorShadowPatcher
                resetter = CursorShadowPatcher()
                patch_success = resetter.reset_machine_ids()
            
            # 更新返回消息
            if success and reset_machine_id and patch_success:
                return {
                    "success": True,
                    "message": f"成功使用账号 {account.email} 的Token并重置了机器ID",
                }
            elif success and reset_machine_id and not patch_success:
                return {
                    "success": True,
                    "message": f"成功使用账号 {account.email} 的Token，但机器ID重置失败",
                }
            elif success:
                return {
                    "success": True,
                    "message": f"成功使用账号 {account.email} 的Token（未重置机器ID）",
                }
            else:
                return {"success": False, "message": "Token更新失败"}

    except Exception as e:
        error(f"使用账号Token失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"使用Token失败: {str(e)}"}

# 添加获取账号使用记录接口
@app.get("/account/{id}/usage-records", tags=["Accounts"])
async def get_account_usage_records(id: int):
    """获取指定账号的使用记录"""
    try:
        async with get_session() as session:
            # 通过ID查询账号
            result = await session.execute(
                select(AccountModel).where(AccountModel.id == id)
            )
            account = result.scalar_one_or_none()

            if not account:
                return {"success": False, "message": f"ID为 {id} 的账号不存在"}
            
            # 查询使用记录
            result = await session.execute(
                select(AccountUsageRecordModel)
                .where(AccountUsageRecordModel.account_id == id)
                .order_by(desc(AccountUsageRecordModel.created_at))
            )
            
            records = result.scalars().all()
            
            # 转换记录为字典列表
            records_list = []
            for record in records:
                records_list.append({
                    "id": record.id,
                    "account_id": record.account_id,
                    "email": record.email,
                    "ip": record.ip,
                    "user_agent": record.user_agent,
                    "created_at": record.created_at
                })
            
            return {
                "success": True,
                "records": records_list
            }

    except Exception as e:
        error(f"获取账号使用记录失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"获取账号使用记录失败: {str(e)}"}

# 添加"重置设备id"功能
@app.get("/reset-machine", tags=["System"])
async def reset_machine():
    """重置设备id"""
    try:
        # 重置Cursor的机器ID
        from cursor_shadow_patcher import CursorShadowPatcher

        resetter = CursorShadowPatcher()
        patch_success = resetter.reset_machine_ids()
        if patch_success:
            return {
                "success": True,
                "message": f"成功重置了机器ID",
            }
        else:
            return {"success": False, "message": "重置机器ID失败"}
    except Exception as e:
        error(f"重置机器ID失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"重置机器ID失败: {str(e)}"}


# 添加配置相关模型
class ConfigModel(BaseModel):
    BROWSER_HEADLESS: bool
    DYNAMIC_USERAGENT: Optional[bool] = False
    BROWSER_USER_AGENT: str
    MAX_ACCOUNTS: int
    EMAIL_DOMAINS: str
    EMAIL_USERNAME: str
    EMAIL_PIN: str
    BROWSER_PATH: Optional[str] = None
    CURSOR_PATH: Optional[str] = None
    USE_PROXY: Optional[bool] = False
    PROXY_TYPE: Optional[str] = None
    PROXY_HOST: Optional[str] = None
    PROXY_PORT: Optional[str] = None
    PROXY_TIMEOUT: Optional[int] = None
    PROXY_USERNAME: Optional[str] = None
    PROXY_PASSWORD: Optional[str] = None
    EMAIL_CODE_TYPE: str = "AUTO"  # 默认值为AUTO


# 获取配置端点
@app.get("/config", tags=["Config"])
async def get_config():
    """获取当前系统配置"""
    try:
        # 重新加载配置以确保获取最新值
        load_dotenv()

        config = {
            "BROWSER_HEADLESS": os.getenv("BROWSER_HEADLESS", "True").lower() == "true",
            "BROWSER_USER_AGENT": os.getenv("BROWSER_USER_AGENT", ""),
            "MAX_ACCOUNTS": int(os.getenv("MAX_ACCOUNTS", "10")),
            "EMAIL_TYPE": os.getenv("EMAIL_TYPE", "tempemail"),
            "EMAIL_PROXY_ENABLED": os.getenv("EMAIL_PROXY_ENABLED", "False").lower() == "true",
            "EMAIL_PROXY_ADDRESS": os.getenv("EMAIL_PROXY_ADDRESS", ""),
            "EMAIL_API": os.getenv("EMAIL_API", ""),
            "EMAIL_DOMAINS": os.getenv("EMAIL_DOMAINS", ""),
            "EMAIL_USERNAME": os.getenv("EMAIL_USERNAME", ""),
            "EMAIL_DOMAIN": os.getenv("EMAIL_DOMAIN", ""),
            "EMAIL_PIN": os.getenv("EMAIL_PIN", ""),
            "EMAIL_CODE_TYPE": os.getenv("EMAIL_CODE_TYPE", "AUTO"),
            "BROWSER_PATH": os.getenv("BROWSER_PATH", ""),
            "CURSOR_PATH": os.getenv("CURSOR_PATH", ""),
            "DYNAMIC_USERAGENT": os.getenv("DYNAMIC_USERAGENT", "False").lower() == "true",
            # 添加代理配置
            "USE_PROXY": os.getenv("USE_PROXY", "False"),
            "PROXY_TYPE": os.getenv("PROXY_TYPE", "http"),
            "PROXY_HOST": os.getenv("PROXY_HOST", ""),
            "PROXY_PORT": os.getenv("PROXY_PORT", ""),
            "PROXY_TIMEOUT": os.getenv("PROXY_TIMEOUT", "10"),
            "PROXY_USERNAME": os.getenv("PROXY_USERNAME", ""),
            "PROXY_PASSWORD": os.getenv("PROXY_PASSWORD", ""),
        }
        
        return {"success": True, "data": config}
    except Exception as e:
        error(f"获取配置失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"获取配置失败: {str(e)}"}


# 更新配置端点
@app.post("/config", tags=["Config"])
async def update_config(config: ConfigModel):
    """更新配置"""
    try:
        # 获取.env文件路径
        env_path = Path(__file__).parent / ".env"

        # 读取当前.env文件内容
        current_lines = []
        if env_path.exists():
            with open(env_path, "r", encoding="utf-8") as f:
                current_lines = f.readlines()

        # 构建配置字典 - 修正：直接使用模型属性而非get方法
        config_dict = {
            "BROWSER_HEADLESS": str(config.BROWSER_HEADLESS),
            "DYNAMIC_USERAGENT": str(config.DYNAMIC_USERAGENT),
            "BROWSER_USER_AGENT": config.BROWSER_USER_AGENT,
            "MAX_ACCOUNTS": str(config.MAX_ACCOUNTS),
            "EMAIL_DOMAINS": config.EMAIL_DOMAINS,
            "EMAIL_USERNAME": config.EMAIL_USERNAME,
            "EMAIL_PIN": config.EMAIL_PIN,
            "EMAIL_CODE_TYPE": config.EMAIL_CODE_TYPE,
            # 添加代理配置
            "USE_PROXY": str(config.USE_PROXY),
            "PROXY_TYPE": config.PROXY_TYPE,
            "PROXY_HOST": config.PROXY_HOST,
            "PROXY_PORT": config.PROXY_PORT,
            "PROXY_TIMEOUT": str(config.PROXY_TIMEOUT),
            "PROXY_USERNAME": config.PROXY_USERNAME,
            "PROXY_PASSWORD": config.PROXY_PASSWORD,
        }

        # 添加可选配置（如果提供）
        if config.BROWSER_PATH:
            config_dict["BROWSER_PATH"] = config.BROWSER_PATH
        if config.CURSOR_PATH:
            config_dict["CURSOR_PATH"] = config.CURSOR_PATH

        # 处理现有行或创建新行
        updated_lines = []
        updated_keys = set()

        for line in current_lines:
            line = line.strip()
            if not line or line.startswith("#"):
                updated_lines.append(line)
                continue

            key, value = line.split("=", 1) if "=" in line else (line, "")
            key = key.strip()

            if key in config_dict:
                updated_lines.append(f"{key}={config_dict[key]}")
                updated_keys.add(key)
            else:
                updated_lines.append(line)

        # 添加未更新的配置项
        for key, value in config_dict.items():
            if key not in updated_keys and value:
                updated_lines.append(f"{key}={value}")

        # 写入更新后的配置
        with open(env_path, "w", encoding="utf-8") as f:
            f.write("\n".join(updated_lines))

        # 重新加载环境变量
        load_dotenv(override=True)

        return {"success": True, "message": "配置已更新"}
    except Exception as e:
        error(f"更新配置失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"更新配置失败: {str(e)}"}


# 优化重启API功能，解决卡住问题
@app.post("/restart", tags=["System"])
async def restart_service():
    """重启应用服务"""
    try:
        info("收到重启服务请求")
        
        # 使用更简单的重启方法 - 通过reload环境变量触发uvicorn重载
        # 1. 修改.env文件，添加/更新一个时间戳，触发热重载
        env_path = os.path.join(os.getcwd(), ".env")
        timestamp = str(int(time.time()))
        
        # 读取现有.env文件
        if os.path.exists(env_path):
            with open(env_path, "r", encoding="utf-8") as f:
                env_lines = f.read().splitlines()
        else:
            env_lines = []
            
        # 更新或添加RESTART_TIMESTAMP变量
        timestamp_found = False
        for i, line in enumerate(env_lines):
            if line.startswith("RESTART_TIMESTAMP="):
                env_lines[i] = f"RESTART_TIMESTAMP={timestamp}"
                timestamp_found = True
                break
                
        if not timestamp_found:
            env_lines.append(f"RESTART_TIMESTAMP={timestamp}")
            
        # 写回.env文件
        with open(env_path, "w", encoding="utf-8") as f:
            f.write("\n".join(env_lines))
            
        info(f"已更新重启时间戳: {timestamp}")
        
        # 仅提示用户手动刷新页面
        return {
            "success": True, 
            "message": "配置已更新，请手动刷新页面以应用更改。"
        }
    except Exception as e:
        error(f"重启服务失败: {str(e)}")
        error(traceback.format_exc())
        return {"success": False, "message": f"重启服务失败: {str(e)}"}


@app.post("/update_all_usage", tags=["Accounts"])
async def update_all_accounts_usage():
    """更新所有账户的使用量信息"""
    try:
        async with get_session() as session:
            # 查询所有账号
            result = await session.execute(select(AccountModel))
            accounts = result.scalars().all()
            
            updated_count = 0
            error_count = 0
            
            for account in accounts:
                try:
                    # 获取账号使用量
                    remaining_balance = Cursor.get_remaining_balance(
                        account.user, account.token
                    )
                    remaining_days = Cursor.get_trial_remaining_days(
                        account.user, account.token
                    )
                    
                    # 更新数据库
                    if remaining_balance is not None:
                        total_limit = 150  # 默认总额度
                        used_limit = total_limit - remaining_balance
                        
                        if remaining_days is not None and remaining_days == 0:
                            account.status = "disabled"
                            
                        # 更新数据库中的usage_limit字段
                        account.usage_limit = str(remaining_balance)
                        updated_count += 1
                    else:
                        error_count += 1
                        
                except Exception as e:
                    error_count += 1
                    logger.error(f"更新账户 {account.email} 失败: {str(e)}")
            
            # 提交所有更改
            await session.commit()
            
            return {
                "success": True,
                "message": f"成功更新 {updated_count} 个账户，失败 {error_count} 个"
            }
            
    except Exception as e:
        logger.error(f"批量更新账户余量失败: {str(e)}")
        return {"success": False, "message": str(e)}


if __name__ == "__main__":
    uvicorn.run(
        "api:app",
        host=API_HOST,
        port=API_PORT,
        reload=API_DEBUG,
        access_log=True,
        log_level="error",
        workers=API_WORKERS,
        loop="asyncio",  # Windows下使用默认的asyncio
    )