from fastapi import APIRouter, Depends, HTTPException, Query, Body
from sqlalchemy.orm import Session
from typing import Optional, List, Dict, Any
from ...shared.config.database import get_db
from ...security.middleware.auth import authorize_roles, get_current_user
from ...auth.models.user import User
from ..models.workflow import TaskStatus, TaskPriority
from ...hotel_services.services.task_service import TaskService
from pydantic import BaseModel
from datetime import datetime

router = APIRouter(prefix='/tasks', tags=['tasks'])

# Request/Response Models
class TaskCreate(BaseModel):
    title: str
    description: Optional[str] = None
    task_type: str = 'general'
    priority: Optional[str] = 'medium'
    workflow_instance_id: Optional[int] = None
    booking_id: Optional[int] = None
    room_id: Optional[int] = None
    assigned_to: Optional[int] = None
    due_date: Optional[str] = None
    estimated_duration_minutes: Optional[int] = None
    metadata: Optional[Dict[str, Any]] = None

class TaskUpdate(BaseModel):
    title: Optional[str] = None
    description: Optional[str] = None
    status: Optional[str] = None
    priority: Optional[str] = None
    assigned_to: Optional[int] = None
    due_date: Optional[str] = None
    notes: Optional[str] = None
    actual_duration_minutes: Optional[int] = None

class TaskCommentCreate(BaseModel):
    comment: str

# Task CRUD
@router.post('/')
async def create_task(
    task_data: TaskCreate,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Create a new task"""
    try:
        due_date = None
        if task_data.due_date:
            try:
                due_date = datetime.fromisoformat(task_data.due_date.replace('Z', '+00:00'))
            except:
                due_date = datetime.strptime(task_data.due_date, '%Y-%m-%dT%H:%M:%S')
        
        task = TaskService.create_task(
            db=db,
            title=task_data.title,
            created_by=current_user.id,
            task_type=task_data.task_type,
            description=task_data.description,
            priority=TaskPriority(task_data.priority) if task_data.priority else TaskPriority.medium,
            workflow_instance_id=task_data.workflow_instance_id,
            booking_id=task_data.booking_id,
            room_id=task_data.room_id,
            assigned_to=task_data.assigned_to,
            due_date=due_date,
            estimated_duration_minutes=task_data.estimated_duration_minutes,
            metadata=task_data.metadata
        )
        return {'status': 'success', 'data': {
            'id': task.id,
            'title': task.title,
            'status': task.status.value,
            'priority': task.priority.value,
            'created_at': task.created_at.isoformat()
        }}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/')
async def get_tasks(
    assigned_to: Optional[int] = Query(None),
    created_by: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    priority: Optional[str] = Query(None),
    task_type: Optional[str] = Query(None),
    booking_id: Optional[int] = Query(None),
    room_id: Optional[int] = Query(None),
    workflow_instance_id: Optional[int] = Query(None),
    overdue_only: bool = Query(False),
    skip: int = Query(0, ge=0),
    limit: int = Query(100, ge=1, le=1000),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get tasks"""
    try:
        tasks = TaskService.get_tasks(
            db=db,
            assigned_to=assigned_to,
            created_by=created_by,
            status=TaskStatus(status) if status else None,
            priority=TaskPriority(priority) if priority else None,
            task_type=task_type,
            booking_id=booking_id,
            room_id=room_id,
            workflow_instance_id=workflow_instance_id,
            overdue_only=overdue_only,
            skip=skip,
            limit=limit
        )
        
        # Build response data safely
        result = []
        for t in tasks:
            try:
                result.append({
                    'id': t.id,
                    'title': t.title,
                    'description': t.description,
                    'task_type': t.task_type,
                    'status': t.status.value,
                    'priority': t.priority.value,
                    'workflow_instance_id': t.workflow_instance_id,
                    'booking_id': t.booking_id,
                    'room_id': t.room_id,
                    'assigned_to': t.assigned_to,
                    'assigned_to_name': t.assignee.full_name if t.assignee else None,
                    'created_by': t.created_by,
                    'due_date': t.due_date.isoformat() if t.due_date else None,
                    'completed_at': t.completed_at.isoformat() if t.completed_at else None,
                    'estimated_duration_minutes': t.estimated_duration_minutes,
                    'actual_duration_minutes': t.actual_duration_minutes,
                    'notes': t.notes,
                    'created_at': t.created_at.isoformat() if t.created_at else None,
                    'updated_at': t.updated_at.isoformat() if t.updated_at else None
                })
            except Exception as task_error:
                # Log the error for this specific task but continue with others
                import logging
                logger = logging.getLogger(__name__)
                logger.error(f"Error serializing task {t.id}: {str(task_error)}")
                continue
        
        return {'status': 'success', 'data': result}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        import logging
        logger = logging.getLogger(__name__)
        logger.error(f"Error in get_tasks: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/my-tasks')
async def get_my_tasks(
    status: Optional[str] = Query(None),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Get tasks assigned to current user"""
    try:
        tasks = TaskService.get_my_tasks(
            db=db,
            user_id=current_user.id,
            status=TaskStatus(status) if status else None
        )
        return {'status': 'success', 'data': [{
            'id': t.id,
            'title': t.title,
            'description': t.description,
            'task_type': t.task_type,
            'status': t.status.value,
            'priority': t.priority.value,
            'due_date': t.due_date.isoformat() if t.due_date else None,
            'created_at': t.created_at.isoformat()
        } for t in tasks]}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/{task_id}')
async def get_task(
    task_id: int,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get task by ID"""
    try:
        task = TaskService.get_task_by_id(db, task_id)
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        comments = TaskService.get_task_comments(db, task_id)
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'title': task.title,
            'description': task.description,
            'task_type': task.task_type,
            'status': task.status.value,
            'priority': task.priority.value,
            'workflow_instance_id': task.workflow_instance_id,
            'booking_id': task.booking_id,
            'room_id': task.room_id,
            'assigned_to': task.assigned_to,
            'assigned_to_name': task.assignee.full_name if task.assignee else None,
            'created_by': task.created_by,
            'created_by_name': task.creator_user.full_name if task.creator_user else None,
            'due_date': task.due_date.isoformat() if task.due_date else None,
            'completed_at': task.completed_at.isoformat() if task.completed_at else None,
            'estimated_duration_minutes': task.estimated_duration_minutes,
            'actual_duration_minutes': task.actual_duration_minutes,
            'notes': task.notes,
            'metadata': task.meta_data,
            'comments': [{
                'id': c.id,
                'user_id': c.user_id,
                'user_name': c.user.full_name if c.user else None,
                'comment': c.comment,
                'created_at': c.created_at.isoformat()
            } for c in comments],
            'created_at': task.created_at.isoformat(),
            'updated_at': task.updated_at.isoformat()
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put('/{task_id}')
async def update_task(
    task_id: int,
    task_data: TaskUpdate,
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Update task"""
    try:
        due_date = None
        if task_data.due_date:
            try:
                due_date = datetime.fromisoformat(task_data.due_date.replace('Z', '+00:00'))
            except:
                due_date = datetime.strptime(task_data.due_date, '%Y-%m-%dT%H:%M:%S')
        
        task = TaskService.update_task(
            db=db,
            task_id=task_id,
            title=task_data.title,
            description=task_data.description,
            status=TaskStatus(task_data.status) if task_data.status else None,
            priority=TaskPriority(task_data.priority) if task_data.priority else None,
            assigned_to=task_data.assigned_to,
            due_date=due_date,
            notes=task_data.notes,
            actual_duration_minutes=task_data.actual_duration_minutes
        )
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'status': task.status.value,
            'updated_at': task.updated_at.isoformat()
        }}
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{task_id}/assign')
async def assign_task(
    task_id: int,
    user_id: int = Body(..., embed=True),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Assign task to a user"""
    try:
        task = TaskService.assign_task(db, task_id, user_id)
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'assigned_to': task.assigned_to,
            'status': task.status.value
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{task_id}/start')
async def start_task(
    task_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Start task (mark as in progress)"""
    try:
        task = TaskService.start_task(db, task_id)
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'status': task.status.value
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{task_id}/complete')
async def complete_task(
    task_id: int,
    notes: Optional[str] = Body(None, embed=True),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Complete task"""
    try:
        task = TaskService.complete_task(db, task_id, notes)
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'status': task.status.value,
            'completed_at': task.completed_at.isoformat() if task.completed_at else None
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{task_id}/cancel')
async def cancel_task(
    task_id: int,
    reason: Optional[str] = Body(None, embed=True),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Cancel task"""
    try:
        task = TaskService.cancel_task(db, task_id, reason)
        if not task:
            raise HTTPException(status_code=404, detail='Task not found')
        
        return {'status': 'success', 'data': {
            'id': task.id,
            'status': task.status.value
        }}
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post('/{task_id}/comments')
async def add_task_comment(
    task_id: int,
    comment_data: TaskCommentCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Add comment to task"""
    try:
        comment = TaskService.add_task_comment(
            db=db,
            task_id=task_id,
            user_id=current_user.id,
            comment=comment_data.comment
        )
        return {'status': 'success', 'data': {
            'id': comment.id,
            'user_id': comment.user_id,
            'user_name': comment.user.full_name if comment.user else None,
            'comment': comment.comment,
            'created_at': comment.created_at.isoformat()
        }}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get('/statistics/')
async def get_task_statistics(
    assigned_to: Optional[int] = Query(None),
    start_date: Optional[str] = Query(None),
    end_date: Optional[str] = Query(None),
    current_user: User = Depends(authorize_roles('admin', 'staff')),
    db: Session = Depends(get_db)
):
    """Get task statistics"""
    try:
        start = None
        end = None
        if start_date:
            start = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
        if end_date:
            end = datetime.fromisoformat(end_date.replace('Z', '+00:00'))
        
        stats = TaskService.get_task_statistics(
            db=db,
            assigned_to=assigned_to or (current_user.id if current_user.role.name != 'admin' else None),
            start_date=start,
            end_date=end
        )
        return {'status': 'success', 'data': stats}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

