from datetime import datetime

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from app.api.deps import User, get_current_user
from app.core.database import get_db
from app.schemas import (
    AnnotationCreate,
    BatchAssignResponse,
    BatchReviewRequest,
    ReviewAnalyticsResponse,
    TaskCreate,
    TaskResponse,
    TaskReview,
    TaskUpdate,
    WorkloadAssignRequest,
)
from app.services.annotation_task_manager import get_annotation_task_manager

from common_logging import get_logger

logger = get_logger(__name__)

router = APIRouter()

@router.post('/', response_model=TaskResponse)
async def create_task(task: TaskCreate, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    result = manager.create_task(title=task.title, description=task.description, content=task.content, task_type=task.task_type, priority=task.priority, deadline=task.deadline, assigned_to=task.assigned_to, created_by=current_user.id, metadata=task.meta_data)
    logger.bind(task_id=result["id"]).info("Task created")
    return result

@router.get('/', response_model=list[TaskResponse])
async def list_tasks(status: str | None=Query(None), task_type: str | None=Query(None), priority: str | None=Query(None), assigned_to: int | None=Query(None), skip: int=Query(0, ge=0), limit: int=Query(50, ge=1, le=200), db: Session=Depends(get_db)):
    from app.models import AnnotationTask
    manager = get_annotation_task_manager(db)
    if assigned_to:
        return manager.get_tasks_by_expert(assigned_to, status)
    query = db.query(AnnotationTask).filter(not AnnotationTask.is_deleted)
    if status:
        query = query.filter(AnnotationTask.status == status)
    if task_type:
        query = query.filter(AnnotationTask.task_type == task_type)
    if priority:
        query = query.filter(AnnotationTask.priority == priority)
    tasks = query.order_by(AnnotationTask.priority.desc(), AnnotationTask.created_at.desc()).offset(skip).limit(limit).all()
    return [manager._task_to_dict(task) for task in tasks]

@router.post('/batch-review', response_model=list[TaskResponse])
async def batch_review_tasks(request: BatchReviewRequest, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        return manager.batch_review(task_ids=request.task_ids, quality_score=request.quality_score, feedback=request.feedback, approved=request.approved, reviewed_by=current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from None

@router.post('/assign-by-workload', response_model=BatchAssignResponse)
async def assign_by_workload(request: WorkloadAssignRequest, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        return manager.assign_by_workload(task_ids=request.task_ids, reviewer_ids=request.reviewer_ids, assigned_by=current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from None

@router.get('/review-analytics', response_model=ReviewAnalyticsResponse)
async def review_analytics(start_time: str | None=Query(None), end_time: str | None=Query(None), reviewed_by: int | None=Query(None), task_type: str | None=Query(None), priority: str | None=Query(None), db: Session=Depends(get_db)):
    manager = get_annotation_task_manager(db)
    try:
        start_dt = datetime.fromisoformat(start_time) if start_time else None
        end_dt = datetime.fromisoformat(end_time) if end_time else None
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from None
    return manager.get_review_analytics(start_time=start_dt, end_time=end_dt, reviewed_by=reviewed_by, task_type=task_type, priority=priority)

@router.get('/{task_id}', response_model=TaskResponse)
async def get_task(task_id: int, db: Session=Depends(get_db)):
    from app.models import AnnotationTask
    task = db.query(AnnotationTask).filter(AnnotationTask.id == task_id, not AnnotationTask.is_deleted).first()
    if not task:
        raise HTTPException(status_code=404, detail='Task not found')
    manager = get_annotation_task_manager(db)
    return manager._task_to_dict(task)

@router.put('/{task_id}/assign', response_model=TaskResponse)
async def assign_task(task_id: int, expert_id: int, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        return manager.assign_task(task_id, expert_id, assigned_by=current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e)) from None

@router.put('/{task_id}/status', response_model=TaskResponse)
async def update_task_status(task_id: int, update: TaskUpdate, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        if update.assigned_to is not None:
            manager.assign_task(task_id, update.assigned_to, assigned_by=current_user.id)
        if update.status:
            logger.bind(task_id=task_id, status=update.status).info("Task status changed")
            return manager.update_status(task_id, update.status, updated_by=current_user.id)
        if update.priority is not None:
            from app.models import AnnotationTask
            task = db.query(AnnotationTask).filter(AnnotationTask.id == task_id, not AnnotationTask.is_deleted).first()
            if not task:
                raise ValueError(f'Task {task_id} not found')
            task.priority = update.priority
            db.commit()
            db.refresh(task)
            return manager._task_to_dict(task)
        return manager.update_status(task_id, update.status, updated_by=current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e)) from None

@router.post('/{task_id}/submit', response_model=TaskResponse)
async def submit_annotation(task_id: int, annotation: AnnotationCreate, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        return manager.submit_annotation(task_id, annotation.annotation_data, submitted_by=current_user.id)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e)) from None

@router.post('/batch-import-to-dataset')
async def batch_import_to_dataset(task_ids: list[int], dataset_id: int=Query(...), split: str=Query('train'), db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    import json as _json

    from app.models import AnnotationTask, DatasetSample, TrainingDataset
    dataset = db.query(TrainingDataset).filter(TrainingDataset.id == dataset_id).first()
    if not dataset:
        raise HTTPException(status_code=404, detail='Dataset not found')
    tasks = db.query(AnnotationTask).filter(AnnotationTask.id.in_(task_ids), not AnnotationTask.is_deleted, AnnotationTask.status == 'reviewed', AnnotationTask.approved).all()
    existing_task_ids = {row.source_task_id for row in db.query(DatasetSample.source_task_id).filter(DatasetSample.dataset_id == dataset_id, DatasetSample.source_task_id.in_(task_ids)).all()}
    imported, skipped = ([], [])
    for task in tasks:
        if task.id in existing_task_ids:
            skipped.append(task.id)
            continue
        sample = DatasetSample(dataset_id=dataset_id, content=_json.dumps(task.annotation_data, ensure_ascii=False), label=task.task_type, split=split, source_task_id=task.id, meta_data={'quality_score': task.quality_score, 'task_title': task.title})
        db.add(sample)
        imported.append(task.id)
    if imported:
        dataset.total_samples += len(imported)
        if split == 'train':
            dataset.train_samples += len(imported)
        elif split == 'validation':
            dataset.validation_samples += len(imported)
        elif split == 'test':
            dataset.test_samples += len(imported)
        db.commit()
    logger.bind(dataset_id=dataset_id, imported_count=len(imported), skipped_count=len(skipped)).info("Batch import to dataset completed")
    return {'dataset_id': dataset_id, 'dataset_name': dataset.name, 'split': split, 'imported_count': len(imported), 'skipped_count': len(skipped), 'imported_task_ids': imported, 'skipped_task_ids': skipped}

@router.post('/{task_id}/import-to-dataset')
async def import_task_to_dataset(task_id: int, dataset_id: int=Query(...), split: str=Query('train'), db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    from app.models import AnnotationTask, DatasetSample, TrainingDataset
    task = db.query(AnnotationTask).filter(AnnotationTask.id == task_id, not AnnotationTask.is_deleted).first()
    if not task:
        raise HTTPException(status_code=404, detail='Task not found')
    if task.status != 'reviewed':
        raise HTTPException(status_code=400, detail='只有已审核（reviewed）的任务才能导入数据集')
    if not task.approved:
        raise HTTPException(status_code=400, detail='只有审核通过的任务才能导入数据集')
    dataset = db.query(TrainingDataset).filter(TrainingDataset.id == dataset_id).first()
    if not dataset:
        raise HTTPException(status_code=404, detail='Dataset not found')
    already = db.query(DatasetSample).filter(DatasetSample.dataset_id == dataset_id, DatasetSample.source_task_id == task_id).first()
    if already:
        raise HTTPException(status_code=409, detail='该任务已导入此数据集')
    import json as _json
    sample = DatasetSample(dataset_id=dataset_id, content=_json.dumps(task.annotation_data, ensure_ascii=False), label=task.task_type, split=split, source_task_id=task_id, meta_data={'quality_score': task.quality_score, 'task_title': task.title})
    db.add(sample)
    dataset.total_samples += 1
    if split == 'train':
        dataset.train_samples += 1
    elif split == 'validation':
        dataset.validation_samples += 1
    elif split == 'test':
        dataset.test_samples += 1
    db.commit()
    db.refresh(sample)
    return {'sample_id': sample.id, 'dataset_id': dataset_id, 'dataset_name': dataset.name, 'split': split, 'task_id': task_id}

@router.post('/{task_id}/review', response_model=TaskResponse)
async def review_annotation(task_id: int, review: TaskReview, db: Session=Depends(get_db), current_user: User=Depends(get_current_user)):
    manager = get_annotation_task_manager(db)
    try:
        return manager.add_review(task_id=task_id, quality_score=review.quality_score, feedback=review.feedback, reviewed_by=current_user.id, approved=review.approved)
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e)) from None
