"""
Admin Service - Tasks Module

包含任务管理相关功能。
"""

import logging
import time
from typing import Optional, Dict, Any, Tuple, List

from sqlmodel import Session, select, func
from datetime import datetime

from src.config.database import engine
from src.models.entities import UserDB, ProjectDB, TaskDB
from src.models.admin_schemas import (
    AdminTaskListItem,
    AdminTaskStatsResponse,
    AdminTaskQueueStatusResponse,
)

logger = logging.getLogger(__name__)


def _timestamp_to_iso(ts: Optional[float]) -> str:
    """Convert timestamp to ISO format string"""
    if not ts:
        return ""
    return datetime.fromtimestamp(ts).isoformat()


class TaskManagementService:
    """Task management service for admin operations"""

    async def list_tasks(
        self,
        page: int = 1,
        page_size: int = 20,
        filters: Optional[Dict[str, Any]] = None,
        sort_by: str = "created_at",
        sort_order: str = "desc",
    ) -> Tuple[List[AdminTaskListItem], int]:
        """List tasks with pagination and filtering"""
        with Session(engine) as session:
            query = select(TaskDB)

            # Apply filters
            if filters:
                if filters.get("status"):
                    query = query.where(TaskDB.status == filters["status"])
                if filters.get("type"):
                    query = query.where(TaskDB.type == filters["type"])
                if filters.get("provider"):
                    query = query.where(TaskDB.provider == filters["provider"])
                if filters.get("user_id"):
                    query = query.where(TaskDB.user_id == filters["user_id"])
                if filters.get("project_id"):
                    query = query.where(TaskDB.project_id == filters["project_id"])

            # Get total count
            total = session.exec(
                select(func.count()).select_from(query.subquery())
            ).one()

            # Apply sorting
            if sort_by == "created_at":
                sort_column = TaskDB.created_at
            elif sort_by == "updated_at":
                sort_column = TaskDB.updated_at
            else:
                sort_column = TaskDB.created_at

            if sort_order.lower() == "desc":
                query = query.order_by(sort_column.desc())
            else:
                query = query.order_by(sort_column.asc())

            # Apply pagination
            offset = (page - 1) * page_size
            query = query.offset(offset).limit(page_size)

            tasks = session.exec(query).all()

            items = []
            for task in tasks:
                # Get user name and email
                user_name = None
                user_email = None
                if task.user_id:
                    user = session.exec(
                        select(UserDB).where(UserDB.id == task.user_id)
                    ).first()
                    if user:
                        user_name = user.username
                        user_email = user.email

                # Get project name
                project_name = None
                if task.project_id:
                    project = session.exec(
                        select(ProjectDB).where(ProjectDB.id == task.project_id)
                    ).first()
                    if project:
                        project_name = project.name

                # Calculate duration in seconds
                duration = None
                if task.started_at and task.completed_at:
                    duration = int(task.completed_at - task.started_at)
                elif task.started_at:
                    # Task is still running
                    duration = int(time.time() - task.started_at)

                items.append(
                    AdminTaskListItem(
                        id=task.id,
                        type=task.type,
                        status=task.status,
                        model=task.model,
                        provider=task.provider,
                        created_at=_timestamp_to_iso(task.created_at),
                        updated_at=_timestamp_to_iso(task.updated_at),
                        started_at=_timestamp_to_iso(task.started_at),
                        completed_at=_timestamp_to_iso(task.completed_at),
                        duration=duration,
                        user_id=task.user_id,
                        user_name=user_name,
                        user_email=user_email,
                        project_id=task.project_id,
                        project_name=project_name,
                        retry_count=task.retry_count,
                        max_retries=task.max_retries,
                        error=task.error,
                    )
                )

            return items, total

    async def get_task_detail(self, task_id: str) -> Optional[AdminTaskListItem]:
        """Get task detail by ID"""
        with Session(engine) as session:
            task = session.get(TaskDB, task_id)
            if not task:
                return None

            # Get user name and email
            user_name = None
            user_email = None
            if task.user_id:
                user = session.exec(
                    select(UserDB).where(UserDB.id == task.user_id)
                ).first()
                if user:
                    user_name = user.username
                    user_email = user.email

            # Get project name
            project_name = None
            if task.project_id:
                project = session.exec(
                    select(ProjectDB).where(ProjectDB.id == task.project_id)
                ).first()
                if project:
                    project_name = project.name

            # Calculate duration in seconds
            duration = None
            if task.started_at and task.completed_at:
                duration = int(task.completed_at - task.started_at)
            elif task.started_at:
                # Task is still running
                duration = int(time.time() - task.started_at)

            return AdminTaskListItem(
                id=task.id,
                type=task.type,
                status=task.status,
                model=task.model,
                provider=task.provider,
                created_at=_timestamp_to_iso(task.created_at),
                updated_at=_timestamp_to_iso(task.updated_at),
                started_at=_timestamp_to_iso(task.started_at),
                completed_at=_timestamp_to_iso(task.completed_at),
                duration=duration,
                user_id=task.user_id,
                user_name=user_name,
                user_email=user_email,
                project_id=task.project_id,
                project_name=project_name,
                retry_count=task.retry_count,
                max_retries=task.max_retries,
                error=task.error,
            )

    async def get_task_stats(self) -> AdminTaskStatsResponse:
        """Get task statistics"""
        with Session(engine) as session:
            # Count by status
            status_counts = {}
            for status in ["pending", "processing", "success", "failed", "timeout", "retrying"]:
                count = session.exec(
                    select(func.count()).select_from(TaskDB).where(TaskDB.status == status)
                ).one()
                status_counts[status] = count

            # Count by type
            type_counts = {}
            for task_type in ["image", "video", "audio", "music", "script"]:
                count = session.exec(
                    select(func.count()).select_from(TaskDB).where(TaskDB.type == task_type)
                ).one()
                type_counts[task_type] = count

            # Count by provider
            providers = session.exec(
                select(TaskDB.provider, func.count())
                .where(TaskDB.provider.is_not(None))
                .group_by(TaskDB.provider)
            ).all()
            provider_counts = {p[0]: p[1] for p in providers}

            # Total count
            total = session.exec(select(func.count()).select_from(TaskDB)).one()

            # Success rate
            success_count = status_counts.get("success", 0)
            failed_count = status_counts.get("failed", 0)
            completed_count = success_count + failed_count
            success_rate = (success_count / completed_count * 100) if completed_count > 0 else 0.0

            # Average processing time
            completed_tasks = session.exec(
                select(TaskDB).where(
                    TaskDB.status == "success",
                    TaskDB.started_at.is_not(None),
                    TaskDB.completed_at.is_not(None),
                )
            ).all()

            avg_processing_time = None
            if completed_tasks:
                total_time = sum(
                    task.completed_at - task.started_at for task in completed_tasks
                )
                avg_processing_time = total_time / len(completed_tasks)

            return AdminTaskStatsResponse(
                total=total,
                by_status=status_counts,
                by_type=type_counts,
                by_provider=provider_counts,
                avg_processing_time=avg_processing_time,
                success_rate=success_rate,
            )

    async def get_task_queue_status(self) -> AdminTaskQueueStatusResponse:
        """Get task queue status"""
        with Session(engine) as session:
            pending = session.exec(
                select(func.count()).select_from(TaskDB).where(TaskDB.status == "pending")
            ).one()

            processing = session.exec(
                select(func.count()).select_from(TaskDB).where(TaskDB.status == "processing")
            ).one()

            retrying = session.exec(
                select(func.count()).select_from(TaskDB).where(TaskDB.status == "retrying")
            ).one()

        # Get task manager info if available
        try:
            from src.services.task_manager import task_manager

            max_workers = task_manager.max_workers
            active_workers = len(task_manager._active_tasks)
        except Exception:
            max_workers = 0
            active_workers = 0

        return AdminTaskQueueStatusResponse(
            queue_length=pending,
            processing_count=processing,
            max_workers=max_workers,
            active_workers=active_workers,
            pending_tasks=pending,
            retry_tasks=retrying,
        )

    async def retry_task(self, task_id: str) -> Optional[TaskDB]:
        """Retry a failed task"""
        with Session(engine) as session:
            task = session.exec(select(TaskDB).where(TaskDB.id == task_id)).first()

            if not task:
                return None

            # Only allow retry for failed or timeout tasks
            if task.status not in ["failed", "timeout"]:
                return None

            # Reset task status
            task.status = "pending"
            task.retry_count = 0
            task.error = None
            task.updated_at = datetime.now().timestamp()

            session.add(task)
            session.commit()
            session.refresh(task)

            return task

    async def delete_task(self, task_id: str) -> bool:
        """Delete a task"""
        with Session(engine) as session:
            task = session.exec(select(TaskDB).where(TaskDB.id == task_id)).first()

            if not task:
                return False

            session.delete(task)
            session.commit()
            return True
