from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import selectinload, aliased
from sqlalchemy import and_, or_
from fastapi.responses import FileResponse
import os
import uuid

from database import get_db
from models import Task, Project, User, KanbanColumn, TaskLink, TaskAttachment, AuditLog, TaskComment, ProjectComment, Tag, TaskProgressHistory, Subtask, Team, Notification, Holiday, SystemSetting, ProjectRoadmapVersion, ProjectReportVersion
from schemas import TaskCreate, TaskResponse, ProjectResponse, ProjectCreate, ProjectUpdate, KanbanColumnResponse, KanbanColumnCreate, KanbanColumnUpdate, UserResponse, TaskLinkCreate, TaskLinkResponse, TaskAttachmentResponse, CommentCreate, CommentResponse, TagCreate, TagResponse, SubtaskCreate, SubtaskResponse, RoadmapCreate, HolidayResponse, SystemSettingResponse, RoadmapVersionResponse, ReportVersionResponse
from auth import get_current_active_user, require_roles, require_projects_access
from datetime import datetime, timedelta
from typing import List

UPLOAD_DIR = os.getenv("UPLOAD_DIR", os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "uploads"))
os.makedirs(UPLOAD_DIR, exist_ok=True)


router = APIRouter(prefix="/api/v1/kanban", tags=["kanban"], dependencies=[Depends(require_projects_access)])

async def create_notification(db: AsyncSession, user_id: int, message: str, link: str = None):
    if user_id:
        notif = Notification(user_id=user_id, message=message, link=link)
        db.add(notif)

@router.get("/users", response_model=list[UserResponse])
async def get_users(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(User).where(User.company_id == current_user.company_id).options(selectinload(User.roles))
    result = await db.execute(stmt)
    return result.scalars().all()

@router.get("/projects", response_model=List[ProjectResponse])
async def get_projects(
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    try:
        is_superadmin = any(role.name == "Super Administrador" for role in current_user.roles)
        has_admin_role = any(role.name == "Administrador" for role in current_user.roles)
        if current_user.is_admin or has_admin_role or is_superadmin:
            stmt = select(Project).where(Project.is_archived == False)
            if not is_superadmin:
                stmt = stmt.where(Project.company_id == current_user.company_id)
            
            stmt = stmt.options(
                selectinload(Project.company),
                selectinload(Project.team).selectinload(Team.members).selectinload(User.roles), 
                selectinload(Project.team).selectinload(Team.members).selectinload(User.company), 
                selectinload(Project.assignee).selectinload(User.roles),
                selectinload(Project.assignee).selectinload(User.company),
                selectinload(Project.viewers)
            ).distinct()
        else:
            ViewerUser = aliased(User)
            stmt = select(Project).outerjoin(Project.team).outerjoin(Team.members).outerjoin(Project.viewers.of_type(ViewerUser)).where(
                and_(
                    Project.company_id == current_user.company_id,
                    Project.is_archived == False,
                    or_(
                        Project.is_public == True, 
                        Project.creator_id == current_user.id,
                        Project.assignee_id == current_user.id,
                        User.id == current_user.id,
                        ViewerUser.id == current_user.id
                    )
                )
            ).options(
                selectinload(Project.company),
                selectinload(Project.team).selectinload(Team.members).selectinload(User.roles), 
                selectinload(Project.team).selectinload(Team.members).selectinload(User.company), 
                selectinload(Project.assignee).selectinload(User.roles),
                selectinload(Project.assignee).selectinload(User.company),
                selectinload(Project.viewers)
            ).distinct()

        result = await db.execute(stmt)
        return result.scalars().all()
    except Exception as e:
        import traceback
        from fastapi import JSONResponse
        return JSONResponse(status_code=500, content={"error": str(e), "traceback": traceback.format_exc()})

@router.post("/projects", response_model=ProjectResponse)
async def create_project(
    project: ProjectCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    proj_data = project.model_dump()
    proj_data['creator_id'] = current_user.id
    proj_data['company_id'] = current_user.company_id
    db_proj = Project(**proj_data)

    db.add(db_proj)
    await db.commit()
    await db.refresh(db_proj)
    
    # Auto-seed columns
    default_columns = [
        KanbanColumn(name="Por Hacer", order=1, project_id=db_proj.id),
        KanbanColumn(name="En Progreso", order=2, project_id=db_proj.id),
        KanbanColumn(name="Revisión", order=3, project_id=db_proj.id),
        KanbanColumn(name="Hecho", order=4, project_id=db_proj.id)
    ]
    db.add_all(default_columns)
    
    # Audit log
    audit = AuditLog(user_id=current_user.id, username=current_user.username, action=f"Creó el proyecto '{project.name}'")
    db.add(audit)
    
    await db.commit()
    
    # Reload with relations
    stmt_reload = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == db_proj.id).options(selectinload(Project.team), selectinload(Project.assignee))
    result = await db.execute(stmt_reload)
    return result.scalar_one()

@router.put("/projects/{project_id}", response_model=ProjectResponse)
async def update_project(
    project_id: int,
    project_update: ProjectUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id).options(selectinload(Project.team), selectinload(Project.assignee))
    result = await db.execute(stmt)
    db_proj = result.scalar_one_or_none()
    if not db_proj:
        raise HTTPException(status_code=404, detail="Project not found")
        
    await check_project_edit_permission(db, project_id, current_user)
        
    if project_update.name is not None:
        db_proj.name = project_update.name
    if project_update.description is not None:
        db_proj.description = project_update.description
    if project_update.is_public is not None:
        db_proj.is_public = project_update.is_public
    if project_update.roadmap_objectives is not None:
        db_proj.roadmap_objectives = project_update.roadmap_objectives
    if project_update.roadmap_deliverables is not None:
        db_proj.roadmap_deliverables = project_update.roadmap_deliverables
    if project_update.roadmap_strategy is not None:
        db_proj.roadmap_strategy = project_update.roadmap_strategy
    if project_update.roadmap_resources is not None:
        db_proj.roadmap_resources = project_update.roadmap_resources
    if project_update.roadmap_deadlines is not None:
        db_proj.roadmap_deadlines = project_update.roadmap_deadlines
    if project_update.roadmap_stakeholders is not None:
        db_proj.roadmap_stakeholders = project_update.roadmap_stakeholders
        
    old_assignee = db_proj.assignee_id
    if project_update.assignee_id is not None or project_update.team_id is not None:
        # If one is passed, update it. For unified:
        db_proj.assignee_id = project_update.assignee_id
        db_proj.team_id = project_update.team_id
        
    if old_assignee != db_proj.assignee_id and db_proj.assignee_id is not None and db_proj.assignee_id != current_user.id:
        await create_notification(db, db_proj.assignee_id, f"Se te ha asignado el proyecto: {db_proj.name}", link="/index.html")
        
    # Audit log
    audit = AuditLog(user_id=current_user.id, username=current_user.username, action=f"Actualizó el proyecto '{db_proj.name}'")
    db.add(audit)
        
    await db.commit()
    await db.refresh(db_proj)
    return db_proj

@router.delete("/projects/{project_id}")
async def delete_project(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    # Only allow deleting project if it's not Project 1 (or we can just allow deleting any)
    if project_id == 1:
        raise HTTPException(status_code=400, detail="No se puede eliminar el Proyecto Principal")
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    result = await db.execute(stmt)
    db_proj = result.scalar_one_or_none()
    if not db_proj:
        raise HTTPException(status_code=404, detail="Project not found")
        
    db_proj.is_archived = True
    
    # Audit log
    audit = AuditLog(user_id=current_user.id, username=current_user.username, action=f"Archivó el proyecto '{db_proj.name}'")
    db.add(audit)
    
    await db.commit()
    return {"message": "Project archived successfully"}

@router.get("/projects/archived", response_model=list[ProjectResponse])
async def get_archived_projects(
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Project).where(
        Project.company_id == current_user.company_id,
        Project.is_archived == True
    ).options(
        selectinload(Project.team).selectinload(Team.members).selectinload(User.roles), 
        selectinload(Project.team).selectinload(Team.members).selectinload(User.company), 
        selectinload(Project.assignee).selectinload(User.roles),
        selectinload(Project.assignee).selectinload(User.company)
    ).distinct()
    result = await db.execute(stmt)
    return result.scalars().all()

@router.put("/projects/{project_id}/restore")
async def restore_project(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    result = await db.execute(stmt)
    db_proj = result.scalar_one_or_none()
    if not db_proj:
        raise HTTPException(status_code=404, detail="Project not found")
        
    db_proj.is_archived = False
    
    audit = AuditLog(user_id=current_user.id, username=current_user.username, action=f"Restauró el proyecto '{db_proj.name}'")
    db.add(audit)
    
    await db.commit()
    return {"message": "Project restored successfully"}

@router.delete("/projects/{project_id}/permanent")
async def hard_delete_project(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    if project_id == 1:
        raise HTTPException(status_code=400, detail="No se puede eliminar el Proyecto Principal")
        
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    result = await db.execute(stmt)
    db_proj = result.scalar_one_or_none()
    if not db_proj:
        raise HTTPException(status_code=404, detail="Project not found")
        
    audit = AuditLog(user_id=current_user.id, username=current_user.username, action=f"Eliminó permanentemente el proyecto '{db_proj.name}'")
    db.add(audit)
    
    await db.delete(db_proj)
    await db.commit()
    return {"message": "Project permanently deleted"}

@router.get("/tasks/archived", response_model=list[TaskResponse])
async def get_archived_tasks(
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Task).join(Project).where(Project.is_archived == True)
    result = await db.execute(stmt)
    return result.scalars().all()

# --- TASK LINKS (DEPENDENCIES) ---

@router.get("/links", response_model=list[TaskLinkResponse])
async def get_task_links(project_id: int = None, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    if project_id:
        stmt = select(TaskLink).where(TaskLink.project_id == project_id)
    else:
        stmt = select(TaskLink)
    result = await db.execute(stmt)
    return result.scalars().all()

async def check_project_edit_permission(db: AsyncSession, project_id: int, current_user: User):
    is_superadmin = any(role.name == "Super Administrador" for role in current_user.roles)
    has_admin_role = any(role.name == "Administrador" for role in current_user.roles)
    if current_user.is_admin or has_admin_role or is_superadmin:
        return True
    
    stmt = select(Project).options(selectinload(Project.viewers), selectinload(Project.team).selectinload(Team.members)).where(Project.id == project_id)
    res = await db.execute(stmt)
    proj = res.scalar_one_or_none()
    
    if not proj:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    is_viewer = any(v.id == current_user.id for v in proj.viewers)
    is_creator = proj.creator_id == current_user.id
    is_assignee = proj.assignee_id == current_user.id
    is_team = proj.team and any(m.id == current_user.id for m in proj.team.members)
    
    if is_viewer and not (is_creator or is_assignee or is_team):
        raise HTTPException(status_code=403, detail="No tienes permisos para modificar este proyecto (Modo Visualizador)")
        
    return True

async def check_circular_dependency(db: AsyncSession, new_source: int, new_target: int, project_id: int):
    stmt = select(TaskLink).where(TaskLink.project_id == project_id)
    result = await db.execute(stmt)
    links = result.scalars().all()
    
    graph = {}
    for l in links:
        if l.source_id not in graph: graph[l.source_id] = []
        graph[l.source_id].append(l.target_id)
        
    visited = set()
    queue = [new_target]
    while queue:
        current = queue.pop(0)
        if current == new_source: return True
        if current not in visited:
            visited.add(current)
            if current in graph:
                queue.extend(graph[current])
    return False

@router.post("/links", response_model=TaskLinkResponse)
async def create_task_link(link: TaskLinkCreate, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    if await check_circular_dependency(db, link.source_id, link.target_id, link.project_id):
        raise HTTPException(status_code=400, detail="Circular dependency detected")
        
    db_link = TaskLink(
        source_id=link.source_id,
        target_id=link.target_id,
        type=link.type,
        project_id=link.project_id
    )
    db.add(db_link)
    await db.commit()
    await db.refresh(db_link)
    return db_link

@router.delete("/links/{link_id}")
async def delete_task_link(link_id: int, db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    stmt = select(TaskLink).where(TaskLink.id == link_id)
    result = await db.execute(stmt)
    link = result.scalar_one_or_none()
    if not link:
        raise HTTPException(status_code=404, detail="Link not found")
        
    await db.delete(link)
    await db.commit()
    return {"status": "success"}

@router.get("/projects/{project_id}/columns", response_model=list[KanbanColumnResponse])
async def get_columns(
    project_id: str, 
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    if project_id == "all":
        return [
            KanbanColumnResponse(id=1001, project_id=0, name="Por Hacer", order=1),
            KanbanColumnResponse(id=1002, project_id=0, name="En Progreso", order=2),
            KanbanColumnResponse(id=1003, project_id=0, name="Revisión", order=3),
            KanbanColumnResponse(id=1004, project_id=0, name="Hecho", order=4)
        ]
    stmt = select(KanbanColumn).where(KanbanColumn.project_id == int(project_id)).order_by(KanbanColumn.order)
    result = await db.execute(stmt)
    return result.scalars().all()

@router.post("/projects/{project_id}/columns", response_model=KanbanColumnResponse)
async def create_column(
    project_id: int,
    column: KanbanColumnCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    db_col = KanbanColumn(**column.model_dump(), project_id=project_id)
    db.add(db_col)
    await db.commit()
    await db.refresh(db_col)
    return db_col

@router.put("/projects/{project_id}/columns/{column_id}", response_model=KanbanColumnResponse)
async def update_column(
    project_id: int,
    column_id: int,
    column_update: KanbanColumnUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    stmt = select(KanbanColumn).where(KanbanColumn.id == column_id, KanbanColumn.project_id == project_id)
    result = await db.execute(stmt)
    db_col = result.scalar_one_or_none()
    if not db_col:
        raise HTTPException(status_code=404, detail="Columna no encontrada")
    
    if column_update.name is not None:
        db_col.name = column_update.name
    if column_update.order is not None:
        db_col.order = column_update.order
        
    await db.commit()
    await db.refresh(db_col)
    return db_col

@router.delete("/projects/{project_id}/columns/{column_id}")
async def delete_column(
    project_id: int,
    column_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    # Verify if it's the last column
    stmt_count = select(KanbanColumn).where(KanbanColumn.project_id == project_id)
    result_count = await db.execute(stmt_count)
    all_cols = result_count.scalars().all()
    if len(all_cols) <= 1:
        raise HTTPException(status_code=400, detail="No puedes eliminar la última columna del proyecto")
        
    db_col = next((c for c in all_cols if c.id == column_id), None)
    if not db_col:
        raise HTTPException(status_code=404, detail="Columna no encontrada")
        
    # Reassign tasks to the first available column (different from the deleted one)
    target_col = next((c for c in sorted(all_cols, key=lambda x: x.order) if c.id != column_id), None)
    if target_col:
        stmt_tasks = select(Task).where(Task.column_id == column_id)
        result_tasks = await db.execute(stmt_tasks)
        tasks = result_tasks.scalars().all()
        for t in tasks:
            t.column_id = target_col.id
            
    await db.delete(db_col)
    await db.commit()
    return {"status": "success"}
@router.get("/projects/{project_id}/tasks", response_model=list[TaskResponse])
async def get_tasks(
    project_id: str, 
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    is_superadmin = any(role.name == "Super Administrador" for role in current_user.roles)
    
    if project_id == "all":
        stmt = select(Task).join(Task.project).options(selectinload(Task.assignee), selectinload(Task.team), selectinload(Task.attachments), selectinload(Task.column), selectinload(Task.project), selectinload(Task.tags), selectinload(Task.subtasks)).order_by(Task.order, Task.id)
        if not is_superadmin:
            stmt = stmt.where(Project.company_id == current_user.company_id)
        result = await db.execute(stmt)
        tasks = result.scalars().all()
        for t in tasks:
            if t.column:
                name = t.column.name.lower()
                if "hacer" in name or "to do" in name: t.column_id = 1001
                elif "progre" in name or "progress" in name: t.column_id = 1002
                elif "revis" in name or "review" in name: t.column_id = 1003
                else: t.column_id = 1004
        return tasks
        
    stmt = select(Task).join(Task.project).where(Task.project_id == int(project_id))
    if not is_superadmin:
        stmt = stmt.where(Project.company_id == current_user.company_id)
    stmt = stmt.options(selectinload(Task.assignee), selectinload(Task.team), selectinload(Task.attachments), selectinload(Task.tags), selectinload(Task.subtasks)).order_by(Task.order, Task.id)
    result = await db.execute(stmt)
    return result.scalars().all()

@router.get("/tasks/me", response_model=list[TaskResponse])
async def get_my_tasks(
    db: AsyncSession = Depends(get_db), 
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Task).outerjoin(Team).outerjoin(Team.members).where(
        or_(
            Task.assignee_id == current_user.id,
            User.id == current_user.id
        )
    ).options(selectinload(Task.assignee), selectinload(Task.team)).distinct().order_by(Task.due_date)
    result = await db.execute(stmt)
    return result.scalars().all()

@router.post("/tasks", response_model=TaskResponse)
async def create_task(
    task: TaskCreate, 
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Miembro"]))
):
    await check_project_edit_permission(db, task.project_id, current_user)
    db_task = Task(**task.model_dump())
    db.add(db_task)
    await db.commit()
    await db.refresh(db_task)
    
    if db_task.assignee_id and db_task.assignee_id != current_user.id:
        await create_notification(db, db_task.assignee_id, f"Se te ha asignado la tarea: {db_task.title}", link=f"/index.html")

    
    history = TaskProgressHistory(
        task_id=db_task.id,
        project_id=db_task.project_id,
        progress=db_task.progress
    )
    db.add(history)
    await db.commit()
    await db.refresh(db_task)
    
    stmt_reload = select(Task).where(Task.id == db_task.id).options(selectinload(Task.assignee), selectinload(Task.team), selectinload(Task.attachments), selectinload(Task.tags), selectinload(Task.subtasks))
    res = await db.execute(stmt_reload)
    return res.scalar_one()

@router.put("/tasks/{task_id}", response_model=TaskResponse)
async def update_task(
    task_id: int,
    task_update: TaskCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Miembro"]))
):
    stmt = select(Task).where(Task.id == task_id).options(selectinload(Task.assignee), selectinload(Task.team), selectinload(Task.attachments), selectinload(Task.tags), selectinload(Task.subtasks))
    result = await db.execute(stmt)
    db_task = result.scalar_one_or_none()
    if not db_task:
        raise HTTPException(status_code=404, detail="Task not found")
        
    await check_project_edit_permission(db, db_task.project_id, current_user)
        
    old_progress = db_task.progress
    task_data = task_update.model_dump(exclude_unset=True)
    if 'column_id' in task_data and task_data['column_id'] is not None and task_data['column_id'] >= 1000:
        del task_data['column_id']
        
    old_assignee = db_task.assignee_id
    for key, value in task_data.items():
        setattr(db_task, key, value)
        
    if old_assignee != db_task.assignee_id and db_task.assignee_id is not None and db_task.assignee_id != current_user.id:
        await create_notification(db, db_task.assignee_id, f"Se te ha asignado la tarea: {db_task.title}", link=f"/index.html")
        
    if db_task.progress != old_progress:
        history = TaskProgressHistory(
            task_id=db_task.id,
            project_id=db_task.project_id,
            progress=db_task.progress
        )
        db.add(history)
        
    if "column_id" in task_data:
        stmt_last_col = select(KanbanColumn).where(KanbanColumn.project_id == db_task.project_id).order_by(KanbanColumn.order.desc()).limit(1)
        res_last = await db.execute(stmt_last_col)
        last_col = res_last.scalar_one_or_none()
        if last_col and task_data["column_id"] == last_col.id:
            db_task.completed_at = datetime.utcnow()
        else:
            db_task.completed_at = None
            
    await db.commit()
    
    stmt_reload = select(Task).where(Task.id == db_task.id).options(selectinload(Task.assignee), selectinload(Task.team), selectinload(Task.attachments), selectinload(Task.tags), selectinload(Task.subtasks))
    res = await db.execute(stmt_reload)
    return res.scalar_one()

@router.delete("/tasks/{task_id}")
async def delete_task(
    task_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager"]))
):
    stmt = select(Task).where(Task.id == task_id)
    result = await db.execute(stmt)
    db_task = result.scalar_one_or_none()
    if not db_task:
        raise HTTPException(status_code=404, detail="Task not found")
        
    await check_project_edit_permission(db, db_task.project_id, current_user)
        
    await db.delete(db_task)
    await db.commit()
    return {"message": "Task deleted successfully"}

@router.get("/projects/{project_id}/burndown")
async def get_burndown_chart(
    project_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    if project_id == "all":
        stmt_tasks = select(Task)
    else:
        stmt_tasks = select(Task).where(Task.project_id == int(project_id))
    
    res_tasks = await db.execute(stmt_tasks)
    tasks = res_tasks.scalars().all()
    
    if not tasks:
        return {"labels": [], "ideal": [], "actual": [], "scope": []}
        
    valid_starts = [t.start_date for t in tasks if t.start_date]
    valid_dues = [t.due_date for t in tasks if t.due_date]
    
    start_date = min(valid_starts).date() if valid_starts else datetime.utcnow().date()
    end_date = max(valid_dues).date() if valid_dues else start_date + timedelta(days=7)
    
    if start_date == end_date:
        end_date = start_date + timedelta(days=1)
        
    total_days = (end_date - start_date).days
    total_tasks = len(tasks)
    
    labels = []
    ideal = []
    actual = []
    scope = []
    
    current_date = start_date
    while current_date <= end_date:
        labels.append(current_date.strftime("%Y-%m-%d"))
        
        days_passed = (current_date - start_date).days
        ideal_val = max(0, total_tasks - (total_tasks / total_days) * days_passed)
        ideal.append(round(ideal_val, 2))
        
        scope.append(total_tasks)
        
        completed_count = sum(1 for t in tasks if t.completed_at and t.completed_at.date() <= current_date)
        
        if current_date >= datetime.utcnow().date():
            partial_progress = sum(t.progress for t in tasks if not t.completed_at and t.progress)
            remaining = total_tasks - completed_count - partial_progress
        else:
            remaining = total_tasks - completed_count
            
        # Append to actual always, to show the flat line into the future
        actual.append(round(remaining, 2))
            
        current_date += timedelta(days=1)
        
    return {
        "labels": labels,
        "ideal": ideal,
        "actual": actual,
        "scope": scope
    }

@router.get("/projects/{project_id}/stats")
async def get_project_stats(
    project_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    if project_id == "all":
        stmt = select(Task).join(Project).where(Project.company_id == current_user.company_id)
    else:
        stmt = select(Task).join(Project).where(
            and_(
                Task.project_id == int(project_id),
                Project.company_id == current_user.company_id
            )
        )
    
    res = await db.execute(stmt)
    tasks = res.scalars().all()
    
    if not tasks:
        return {"total_tasks": 0, "progress": 0.0, "start_date": None, "end_date": None, "total_days": 0, "pending_days": 0}
        
    valid_starts = [t.start_date for t in tasks if t.start_date]
    valid_dues = [t.due_date for t in tasks if t.due_date]
    
    start_date = min(valid_starts) if valid_starts else None
    end_date = max(valid_dues) if valid_dues else None
    
    total_days = 0
    pending_days = 0
    elapsed_days = 0
    
    if start_date and end_date:
        start_d = start_date.date() if isinstance(start_date, datetime) else start_date
        end_d = end_date.date() if isinstance(end_date, datetime) else end_date
        today_d = datetime.utcnow().date()
        
        total_days = (end_d - start_d).days
        if total_days < 1: total_days = 1
        
        if today_d < start_d:
            elapsed_days = 0
        elif today_d > end_d:
            elapsed_days = total_days
        else:
            elapsed_days = (today_d - start_d).days

        if today_d < end_d:
            pending_days = (end_d - today_d).days
            if pending_days < 0: pending_days = 0
            
    # Calculate progress based on tasks progress weighted by duration
    total_weight = 0
    completed_weight = 0
    for t in tasks:
        task_days = 1
        if t.start_date and t.due_date:
            task_days = max(1, (t.due_date - t.start_date).days)
        total_weight += task_days
        completed_weight += (task_days * t.progress)
        
    global_progress = (completed_weight / total_weight) if total_weight > 0 else 0.0
    
    return {
        "total_tasks": len(tasks),
        "progress": round(global_progress, 1),
        "start_date": start_date.strftime("%Y-%m-%d") if start_date else None,
        "end_date": end_date.strftime("%Y-%m-%d") if end_date else None,
        "total_days": total_days,
        "pending_days": pending_days,
        "elapsed_days": elapsed_days
    }

@router.get("/projects/{project_id}/scurve")
async def get_s_curve(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt_tasks = select(Task).where(Task.project_id == project_id)
    res_tasks = await db.execute(stmt_tasks)
    tasks = res_tasks.scalars().all()
    
    if not tasks:
        return {"labels": [], "planned": [], "actual": []}
        
    valid_starts = [t.start_date for t in tasks if t.start_date]
    valid_dues = [t.due_date for t in tasks if t.due_date]
    
    start_date = min(valid_starts).date() if valid_starts else datetime.utcnow().date()
    end_date = max(valid_dues).date() if valid_dues else start_date + timedelta(days=7)
    
    if start_date == end_date:
        end_date = start_date + timedelta(days=1)
        
    stmt_hist = select(TaskProgressHistory).where(TaskProgressHistory.project_id == project_id).order_by(TaskProgressHistory.date.asc())
    res_hist = await db.execute(stmt_hist)
    history_logs = res_hist.scalars().all()
    
    # Simulate Planned S-Curve (linear progress for each task)
    total_weight = sum(max(1, (t.due_date - t.start_date).days if t.due_date and t.start_date else 1) for t in tasks)
    
    labels = []
    planned = []
    actual = []
    
    current_date = start_date
    today = datetime.utcnow().date()
    
    while current_date <= end_date:
        labels.append(current_date.strftime("%Y-%m-%d"))
        
        # calculate planned progress up to this date
        planned_val = 0
        for t in tasks:
            task_weight = max(1, (t.due_date - t.start_date).days if t.due_date and t.start_date else 1)
            t_start = t.start_date.date() if t.start_date else current_date
            t_due = t.due_date.date() if t.due_date else current_date
            
            if current_date < t_start:
                continue
            elif current_date >= t_due:
                planned_val += task_weight
            else:
                ratio = (current_date - t_start).days / max(1, (t_due - t_start).days)
                planned_val += (task_weight * ratio)
                
        planned_pct = (planned_val / total_weight) * 100 if total_weight > 0 else 0
        planned.append(round(planned_pct, 2))
        
        # calculate actual progress up to this date
        if current_date <= today:
            actual_val = 0
            for t in tasks:
                task_weight = max(1, (t.due_date - t.start_date).days if t.due_date and t.start_date else 1)
                
                # find the latest history log for this task up to current_date
                task_logs = [log for log in history_logs if log.task_id == t.id and log.date.date() <= current_date]
                latest_prog = task_logs[-1].progress if task_logs else 0
                
                actual_val += (task_weight * latest_prog)
                
            actual_pct = (actual_val / total_weight) * 100 if total_weight > 0 else 0
            actual.append(round(actual_pct, 2))
            
        current_date += timedelta(days=1)
        
    return {
        "labels": labels,
        "planned": planned,
        "actual": actual
    }

# --- SUBTASKS ---

async def update_task_progress(task_id: int, db: AsyncSession):
    stmt = select(Subtask).where(Subtask.task_id == task_id)
    result = await db.execute(stmt)
    subtasks = result.scalars().all()
    
    if not subtasks:
        return
        
    total = len(subtasks)
    completed = sum(1 for s in subtasks if s.is_completed)
    progress_percentage = (completed / total) * 100.0
    
    stmt_task = select(Task).where(Task.id == task_id)
    res_task = await db.execute(stmt_task)
    db_task = res_task.scalar_one_or_none()
    
    if db_task:
        db_task.progress = progress_percentage
        history = TaskProgressHistory(
            task_id=db_task.id,
            project_id=db_task.project_id,
            progress=progress_percentage
        )
        db.add(history)
        await db.commit()

@router.post("/tasks/{task_id}/subtasks", response_model=SubtaskResponse)
async def create_subtask(
    task_id: int,
    subtask: SubtaskCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    db_subtask = Subtask(**subtask.model_dump(), task_id=task_id)
    db.add(db_subtask)
    await db.commit()
    await db.refresh(db_subtask)
    await update_task_progress(task_id, db)
    return db_subtask

@router.put("/subtasks/{subtask_id}/toggle", response_model=SubtaskResponse)
async def toggle_subtask(
    subtask_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Subtask).where(Subtask.id == subtask_id)
    result = await db.execute(stmt)
    db_subtask = result.scalar_one_or_none()
    if not db_subtask:
        raise HTTPException(status_code=404, detail="Subtask not found")
        
    db_subtask.is_completed = not db_subtask.is_completed
    await db.commit()
    await db.refresh(db_subtask)
    await update_task_progress(db_subtask.task_id, db)
    return db_subtask

@router.delete("/subtasks/{subtask_id}")
async def delete_subtask(
    subtask_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Subtask).where(Subtask.id == subtask_id)
    result = await db.execute(stmt)
    db_subtask = result.scalar_one_or_none()
    if not db_subtask:
        raise HTTPException(status_code=404, detail="Subtask not found")
        
    task_id = db_subtask.task_id
    await db.delete(db_subtask)
    await db.commit()
    await update_task_progress(task_id, db)
    return {"message": "Deleted"}

@router.post("/tasks/{task_id}/attachments", response_model=TaskAttachmentResponse)
async def upload_attachment(
    task_id: int,
    file: UploadFile = File(...),
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Task).where(Task.id == task_id)
    res = await db.execute(stmt)
    if not res.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Task not found")
        
    ext = file.filename.split('.')[-1] if '.' in file.filename else ''
    filename = f"{uuid.uuid4().hex}.{ext}"
    filepath = os.path.join(UPLOAD_DIR, filename)
    
    with open(filepath, "wb") as f:
        content = await file.read()
        f.write(content)
        
    attachment = TaskAttachment(
        task_id=task_id,
        filename=file.filename,
        file_path=filepath
    )
    db.add(attachment)
    await db.commit()
    await db.refresh(attachment)
    return attachment

@router.get("/attachments/{attachment_id}")
async def download_attachment(
    attachment_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(TaskAttachment).where(TaskAttachment.id == attachment_id)
    res = await db.execute(stmt)
    attachment = res.scalar_one_or_none()
    if not attachment:
        raise HTTPException(status_code=404, detail="Attachment not found")
    
    if not os.path.exists(attachment.file_path):
        raise HTTPException(status_code=404, detail="File physically missing")
        
    return FileResponse(attachment.file_path, filename=attachment.filename)

@router.delete("/attachments/{attachment_id}")
async def delete_attachment(
    attachment_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(TaskAttachment).where(TaskAttachment.id == attachment_id)
    res = await db.execute(stmt)
    attachment = res.scalar_one_or_none()
    if not attachment:
        raise HTTPException(status_code=404, detail="Attachment not found")
        
    if os.path.exists(attachment.file_path):
        os.remove(attachment.file_path)
        
    await db.delete(attachment)
    await db.commit()
    return {"message": "Attachment deleted"}

# --- COMMENTS / OBSERVATIONS ---

@router.get("/tasks/{task_id}/comments", response_model=list[CommentResponse])
async def get_task_comments(
    task_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(TaskComment).where(TaskComment.task_id == task_id).options(selectinload(TaskComment.user).selectinload(User.roles)).order_by(TaskComment.created_at.desc())
    res = await db.execute(stmt)
    return res.scalars().all()

@router.post("/tasks/{task_id}/comments", response_model=CommentResponse)
async def create_task_comment(
    task_id: int,
    comment: CommentCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    new_comment = TaskComment(
        task_id=task_id,
        user_id=current_user.id,
        content=comment.content
    )
    db.add(new_comment)
    await db.commit()
    await db.refresh(new_comment)
    
    stmt_task = select(Task).where(Task.id == task_id)
    res_task = await db.execute(stmt_task)
    task_obj = res_task.scalar_one_or_none()
    if task_obj and task_obj.assignee_id and task_obj.assignee_id != current_user.id:
        await create_notification(db, task_obj.assignee_id, f"Nuevo comentario en la tarea: {task_obj.title}", link=f"/index.html")

    stmt_reload = select(TaskComment).options(selectinload(TaskComment.user)).where(TaskComment.id == new_comment.id).options(selectinload(TaskComment.user).selectinload(User.roles))
    res = await db.execute(stmt_reload)
    return res.scalar_one()

@router.get("/projects/{project_id}/comments", response_model=list[CommentResponse])
async def get_project_comments(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(ProjectComment).where(ProjectComment.project_id == project_id).options(selectinload(ProjectComment.user).selectinload(User.roles)).order_by(ProjectComment.created_at.desc())
    res = await db.execute(stmt)
    return res.scalars().all()

@router.post("/projects/{project_id}/comments", response_model=CommentResponse)
async def create_project_comment(
    project_id: int,
    comment: CommentCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    new_comment = ProjectComment(
        project_id=project_id,
        user_id=current_user.id,
        content=comment.content
    )
    db.add(new_comment)
    await db.commit()
    await db.refresh(new_comment)
    
    stmt_proj = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    res_proj = await db.execute(stmt_proj)
    proj_obj = res_proj.scalar_one_or_none()
    
    if proj_obj:
        if proj_obj.assignee_id and proj_obj.assignee_id != current_user.id:
            await create_notification(db, proj_obj.assignee_id, f"Nuevo comentario en el proyecto: {proj_obj.name}", link="/index.html")
        if proj_obj.creator_id and proj_obj.creator_id != current_user.id and proj_obj.creator_id != proj_obj.assignee_id:
            await create_notification(db, proj_obj.creator_id, f"Nuevo comentario en el proyecto: {proj_obj.name}", link="/index.html")
    
    stmt = select(ProjectComment).where(ProjectComment.id == new_comment.id).options(selectinload(ProjectComment.user).selectinload(User.roles))
    res = await db.execute(stmt)
    return res.scalar_one()

# --- TAGS ---

@router.get("/projects/{project_id}/tags", response_model=list[TagResponse])
async def get_project_tags(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Tag).where(Tag.project_id == project_id)
    res = await db.execute(stmt)
    return res.scalars().all()

@router.post("/projects/{project_id}/tags", response_model=TagResponse)
async def create_project_tag(
    project_id: int,
    tag: TagCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    db_tag = Tag(project_id=project_id, name=tag.name, color=tag.color)
    db.add(db_tag)
    await db.commit()
    await db.refresh(db_tag)
    return db_tag

@router.delete("/tags/{tag_id}")
async def delete_tag(
    tag_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt = select(Tag).where(Tag.id == tag_id)
    res = await db.execute(stmt)
    db_tag = res.scalar_one_or_none()
    if not db_tag:
        raise HTTPException(status_code=404, detail="Tag not found")
    await db.delete(db_tag)
    await db.commit()
    return {"status": "deleted"}

@router.post("/tasks/{task_id}/tags/{tag_id}")
async def add_tag_to_task(
    task_id: int,
    tag_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt_task = select(Task).where(Task.id == task_id).options(selectinload(Task.tags))
    res_task = await db.execute(stmt_task)
    db_task = res_task.scalar_one_or_none()
    if not db_task: raise HTTPException(status_code=404, detail="Task not found")
    
    stmt_tag = select(Tag).where(Tag.id == tag_id)
    res_tag = await db.execute(stmt_tag)
    db_tag = res_tag.scalar_one_or_none()
    if not db_tag: raise HTTPException(status_code=404, detail="Tag not found")
    
    if db_tag not in db_task.tags:
        db_task.tags.append(db_tag)
        await db.commit()
        
    return {"status": "added"}

@router.delete("/tasks/{task_id}/tags/{tag_id}")
async def remove_tag_from_task(
    task_id: int,
    tag_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    stmt_task = select(Task).where(Task.id == task_id).options(selectinload(Task.tags))
    res_task = await db.execute(stmt_task)
    db_task = res_task.scalar_one_or_none()
    if not db_task: raise HTTPException(status_code=404, detail="Task not found")
    
    db_tag = next((t for t in db_task.tags if t.id == tag_id), None)
    if db_tag:
        db_task.tags.remove(db_tag)
        await db.commit()
        
    return {"status": "removed"}

@router.post("/projects/roadmap/generate")
async def generate_project_roadmap(
    roadmap: RoadmapCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    """
    Genera un proyecto automáticamente a partir de un JSON de Roadmap.
    Crea el proyecto, las columnas (basadas en fases), las tareas y sus dependencias secuenciales.
    """
    try:
        # 1. Crear el proyecto
        new_project = Project(
            name=roadmap.project_name,
            is_public=False,
            creator_id=current_user.id,
            company_id=current_user.company_id
        )
        db.add(new_project)
        await db.flush()
        
        # 2. Inicializar la fecha de inicio del proyecto sin zona horaria
        current_date = roadmap.start_date.replace(tzinfo=None)
        previous_task = None
        
        for p_idx, phase in enumerate(roadmap.phases):
            # Crear columna para la fase
            new_col = KanbanColumn(
                name=phase.name,
                order=p_idx,
                project_id=new_project.id
            )
            db.add(new_col)
            await db.flush()
            
            # Crear las tareas dentro de la fase
            for t_idx, tdef in enumerate(phase.tasks):
                end_date = current_date + timedelta(days=tdef.duration_days)
                
                new_task = Task(
                    title=tdef.name,
                    project_id=new_project.id,
                    column_id=new_col.id,
                    order=t_idx,
                    start_date=current_date,
                    due_date=end_date
                )
                db.add(new_task)
                await db.flush()
                
                # Crear subtareas
                for s_idx, subtask_title in enumerate(tdef.subtasks):
                    new_subtask = Subtask(
                        task_id=new_task.id,
                        title=subtask_title,
                        is_completed=False
                    )
                    db.add(new_subtask)

                
                # Crear dependencia con la tarea anterior
                if previous_task:
                    link = TaskLink(
                        source_id=str(previous_task.id),
                        target_id=str(new_task.id),
                        type="0", # finish_to_start
                        project_id=new_project.id
                    )
                    db.add(link)
                
                previous_task = new_task
                current_date = end_date # La siguiente tarea inicia cuando esta termina
                
        # 3. Registrar auditoría
        audit = AuditLog(
            user_id=current_user.id,
            username=current_user.username,
            action=f"Generó automáticamente el proyecto '{new_project.name}' vía Roadmap"
        )
        db.add(audit)
        
        await db.commit()
        return {"message": "Proyecto generado correctamente", "project_id": new_project.id}
    except Exception as e:
        await db.rollback()
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/holidays", response_model=List[HolidayResponse])
async def get_holidays_kanban(db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    try:
        stmt = select(Holiday).where(Holiday.company_id == current_user.company_id)
        result = await db.execute(stmt)
        return result.scalars().all()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/settings", response_model=List[SystemSettingResponse])
async def get_system_settings_kanban(db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_active_user)):
    try:
        stmt = select(SystemSetting).where(SystemSetting.company_id == current_user.company_id)
        result = await db.execute(stmt)
        return result.scalars().all()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/roadmap_templates")
async def get_custom_roadmap_templates(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    try:
        stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "custom_roadmap_templates")
        result = await db.execute(stmt)
        setting = result.scalar_one_or_none()
        if setting and setting.value:
            import json
            try:
                return json.loads(setting.value)
            except:
                return []
        return []
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/roadmap_templates")
async def save_custom_roadmap_template(
    template: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    try:
        stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "custom_roadmap_templates")
        result = await db.execute(stmt)
        setting = result.scalar_one_or_none()
        
        import json
        templates = []
        if setting and setting.value:
            try:
                templates = json.loads(setting.value)
            except:
                templates = []
                
        # Add new template
        templates.append(template)
        
        if setting:
            setting.value = json.dumps(templates)
        else:
            setting = SystemSetting(
                key="custom_roadmap_templates",
                value=json.dumps(templates),
                company_id=current_user.company_id
            )
            db.add(setting)
            
        await db.commit()
        return {"status": "success", "templates": templates}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/roadmap_templates/{name}")
async def delete_custom_roadmap_template(
    name: str,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    try:
        stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "custom_roadmap_templates")
        result = await db.execute(stmt)
        setting = result.scalar_one_or_none()
        
        import json
        if setting and setting.value:
            try:
                templates = json.loads(setting.value)
                new_templates = [t for t in templates if t.get("name") != name]
                setting.value = json.dumps(new_templates)
                await db.commit()
                return {"status": "success", "templates": new_templates}
            except Exception as e:
                raise HTTPException(status_code=500, detail=str(e))
        return {"status": "success", "templates": []}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/ai/generate_subtasks")
async def ai_generate_subtasks(
    payload: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_active_user)
):
    try:
        # Check if AI is enabled
        stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "ai_copilot_enabled")
        res = await db.execute(stmt)
        setting = res.scalar_one_or_none()
        if not setting or setting.value != "true":
            raise HTTPException(status_code=400, detail="El asistente de IA no está habilitado.")
            
        task_name = payload.get("task_name", "").strip()
        if not task_name:
            raise HTTPException(status_code=400, detail="El nombre de la tarea es requerido.")
            
        # Get Gemini key
        key_stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "gemini_api_key")
        key_res = await db.execute(key_stmt)
        key_setting = key_res.scalar_one_or_none()
        api_key = key_setting.value.strip() if key_setting and key_setting.value else None
        
        # Try calling real AI if key is present
        if api_key:
            try:
                prompt = (
                    f"Dada la siguiente tarea en un proyecto: \"{task_name}\", genera una lista en formato JSON de 3 a 5 subtareas recomendadas para completarla. El JSON debe ser estrictamente del formato: {{\"subtasks\": [\"subtarea 1\", \"subtarea 2\", ...]}}"
                )
                import urllib.request
                import json
                import asyncio
                
                def run_api():
                    url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
                    p_data = {
                        "contents": [{"parts": [{"text": prompt}]}],
                        "generationConfig": {"responseMimeType": "application/json"}
                    }
                    req = urllib.request.Request(
                        url,
                        data=json.dumps(p_data).encode("utf-8"),
                        headers={"Content-Type": "application/json"},
                        method="POST"
                    )
                    with urllib.request.urlopen(req, timeout=10) as response:
                        return json.loads(response.read().decode("utf-8"))
                        
                res_json = await asyncio.to_thread(run_api)
                raw_text = res_json["candidates"][0]["content"]["parts"][0]["text"]
                parsed_res = json.loads(raw_text)
                if "subtasks" in parsed_res:
                    return parsed_res
            except Exception as e:
                print("Gemini API call failed, falling back to local patterns:", e)
                
        # Local fallback
        import re
        tn_lower = task_name.lower()
        if any(k in tn_lower for k in ["login", "auth", "registro", "contrase", "seguridad"]):
            subtasks = [
                "Diseñar interfaz de inicio de sesión",
                "Implementar flujo de autenticación (JWT)",
                "Validación de campos y hashing de contraseña",
                "Pruebas de seguridad y expiración de tokens"
            ]
        elif any(k in tn_lower for k in ["base", "datos", "database", "db", "tabla", "migra"]):
            subtasks = [
                "Diseñar modelo relacional (ER)",
                "Crear scripts de migración SQL",
                "Configurar índices y claves foráneas",
                "Validar conexiones y pruebas de inserción"
            ]
        elif any(k in tn_lower for k in ["landing", "diseño", "maquetado", "frontend", "css", "vista", "pantalla"]):
            subtasks = [
                "Crear estructura HTML semántica responsiva",
                "Estilar componentes con CSS (Tailwind/Vanilla)",
                "Agregar interactividad básica en Javascript",
                "Optimizar carga de imágenes y recursos"
            ]
        elif any(k in tn_lower for k in ["api", "endpoint", "backend", "controlador", "router"]):
            subtasks = [
                "Definir esquemas de entrada y salida (Pydantic)",
                "Crear lógica de negocio en el controlador (Router)",
                "Integrar llamadas a la base de datos",
                "Realizar pruebas unitarias de endpoints"
            ]
        elif any(k in tn_lower for k in ["deploy", "producción", "subir", "servidor", "vps", "docker"]):
            subtasks = [
                "Configurar variables de entorno y variables secretas",
                "Crear archivo Dockerfile y docker-compose.yml",
                "Configurar servidor web y proxy inverso (Nginx)",
                "Asegurar el servidor con certificados SSL (Let's Encrypt)"
            ]
        else:
            subtasks = [
                f"Analizar requerimientos para {task_name}",
                f"Planificar diseño y lógica de {task_name}",
                f"Implementar funcionalidad base de {task_name}",
                f"Verificar correcto funcionamiento de {task_name}"
            ]
            
        return {"subtasks": subtasks}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/projects/{project_id}/report")
async def generate_project_report(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador", "Visualizador"]))
):
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id).options(selectinload(Project.tasks).selectinload(Task.assignee))
    result = await db.execute(stmt)
    project = result.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    col_stmt = select(KanbanColumn).where(KanbanColumn.project_id == project_id).order_by(KanbanColumn.order)
    col_res = await db.execute(col_stmt)
    columns = col_res.scalars().all()
    
    done_col_ids = [c.id for c in columns if c.name.lower() in ['done', 'completado', 'finalizado', 'terminado', 'hecho']]
    if not done_col_ids and columns:
        done_col_ids = [columns[-1].id]
        
    completed_tasks = sum(1 for t in project.tasks if t.column_id in done_col_ids)
    total_tasks = len(project.tasks)
    progress_percentage = round((completed_tasks / total_tasks * 100) if total_tasks > 0 else 0, 1)
    
    # Story Points calculations
    total_sp = sum(t.story_points for t in project.tasks if t.story_points)
    completed_sp = sum(t.story_points for t in project.tasks if t.column_id in done_col_ids and t.story_points)
    sp_progress_percentage = round((completed_sp / total_sp * 100) if total_sp > 0 else 0, 1)
    
    # Overdue & blocked calculations
    now = datetime.utcnow()
    blocked_count = sum(1 for t in project.tasks if t.is_blocked)
    
    # Resources calculations
    total_estimated_hours = sum(t.estimated_hours for t in project.tasks if t.estimated_hours) or 0.0
    total_resource_cost = sum(t.resource_cost for t in project.tasks if t.resource_cost) or 0.0
    completed_resource_cost = sum(t.resource_cost for t in project.tasks if t.column_id in done_col_ids and t.resource_cost) or 0.0
    
    overdue_tasks = []
    close_to_due_tasks = []
    for t in project.tasks:
        if t.column_id not in done_col_ids and t.due_date:
            if t.due_date < now:
                overdue_tasks.append(t)
            elif t.due_date <= now + timedelta(days=3):
                close_to_due_tasks.append(t)
                
    # Workload calculations
    workload = {}
    for t in project.tasks:
        username = t.assignee.username if t.assignee else "Sin Asignar"
        if username not in workload:
            workload[username] = {"total_tasks": 0, "completed_tasks": 0, "total_sp": 0, "completed_sp": 0}
        workload[username]["total_tasks"] += 1
        sp = t.story_points or 0
        workload[username]["total_sp"] += sp
        if t.column_id in done_col_ids:
            workload[username]["completed_tasks"] += 1
            workload[username]["completed_sp"] += sp
    workload_list = [{"username": k, **v} for k, v in workload.items()]
    
    # Milestones calculations (defined by high/critical priority or starting with [HITO])
    milestones = []
    for t in project.tasks:
        is_milestone = False
        if t.title.strip().upper().startswith("[HITO]") or t.title.strip().upper().startswith("HITO:"):
            is_milestone = True
        elif t.priority and t.priority.lower() in ["high", "critical", "alta", "crítica"]:
            is_milestone = True
            
        if is_milestone:
            status = "Completado" if t.column_id in done_col_ids else ("En Progreso" if t.progress > 0 else "Pendiente")
            color = "green" if status == "Completado" else ("orange" if status == "En Progreso" else "red")
            if status != "Completado" and t.due_date and t.due_date < now:
                color = "red"
                status = "Vencido"
            milestones.append({
                "title": t.title,
                "due_date": t.due_date.isoformat() if t.due_date else None,
                "status": status,
                "color": color,
                "description": t.description
            })
    
    column_breakdown = [
        {"name": col.name, "count": sum(1 for t in project.tasks if t.column_id == col.id)}
        for col in columns
    ]
    
    tasks_data = [
        {
            "title": t.title,
            "column": next((c.name for c in columns if c.id == t.column_id), "Sin Estado"),
            "start_date": t.start_date.isoformat() if t.start_date else None,
            "due_date": t.due_date.isoformat() if t.due_date else None,
            "baseline_start_date": t.baseline_start_date.isoformat() if t.baseline_start_date else None,
            "baseline_end_date": t.baseline_end_date.isoformat() if t.baseline_end_date else None,
            "estimated_hours": t.estimated_hours or 0.0,
            "resource_cost": t.resource_cost or 0.0,
            "progress": t.progress or 0,
            "assignee": t.assignee.username if t.assignee else "Sin Asignar"
        }
        for t in project.tasks
    ]
    
    sections = [
        {"title": "1. Objetivos", "content": project.roadmap_objectives or "No definido"},
        {"title": "2. Entregables", "content": project.roadmap_deliverables or "No definido"},
        {"title": "3. Estrategia", "content": project.roadmap_strategy or "No definido"},
        {"title": "4. Recursos", "content": project.roadmap_resources or "No definido"},
        {"title": "5. Plazos", "content": project.roadmap_deadlines or "No definido"},
        {"title": "6. Partes involucradas", "content": project.roadmap_stakeholders or "No definido"},
    ]
    
    # Check if AI is enabled in system settings
    ai_stmt = select(SystemSetting).where(
        SystemSetting.company_id == current_user.company_id
    ).where(SystemSetting.key == "ai_copilot_enabled")
    ai_res = await db.execute(ai_stmt)
    ai_setting = ai_res.scalar_one_or_none()
    ai_enabled = ai_setting.value == "true" if ai_setting else False

    api_key = None
    if ai_enabled:
        key_stmt = select(SystemSetting).where(
            SystemSetting.company_id == current_user.company_id
        ).where(SystemSetting.key == "gemini_api_key")
        key_res = await db.execute(key_stmt)
        key_setting = key_res.scalar_one_or_none()
        api_key = key_setting.value.strip() if key_setting and key_setting.value else None
    
    ai_summary = None
    if api_key:
        try:
            prompt = f"""
Eres un consultor de alta dirección y experto en gestión de riesgos de proyectos.
Genera una síntesis ejecutiva profesional y un análisis detallado de riesgos y mitigación para el proyecto "{project.name}".

Estado cuantitativo actual del proyecto:
- Tareas: {completed_tasks} completadas de {total_tasks} ({progress_percentage}% de avance)
- Esfuerzo (Story Points): {completed_sp} completados de {total_sp} ({sp_progress_percentage}% de avance)
- Tareas bloqueadas actualmente: {blocked_count}
- Tareas atrasadas (vencidas): {len(overdue_tasks)}
- Tareas próximas a vencer (3 días): {len(close_to_due_tasks)}

Distribución de la Hoja de Ruta del proyecto:
- Objetivos: {project.roadmap_objectives or "No definidos"}
- Entregables: {project.roadmap_deliverables or "No definidos"}
- Estrategia: {project.roadmap_strategy or "No definida"}
- Recursos: {project.roadmap_resources or "No definidos"}
- Plazos: {project.roadmap_deadlines or "No definidos"}
- Partes Involucradas: {project.roadmap_stakeholders or "No definidas"}

Redacta en español una evaluación profesional estructurada en dos secciones cortas (máximo 150 palabras cada una):
1. **Síntesis Ejecutiva de Progreso**: Analiza la salud general del proyecto combinando el avance físico y el esfuerzo en Story Points.
2. **Análisis de Riesgos y Mitigación**: Diagnostica las amenazas críticas basándote en las tareas bloqueadas/atrasadas y plazos, y recomienda acciones correctivas de mitigación para encarrilar el proyecto.
"""
            import urllib.request
            import json
            import asyncio
            
            def run_api():
                url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
                p_data = {
                    "contents": [{"parts": [{"text": prompt}]}]
                }
                req = urllib.request.Request(
                    url,
                    data=json.dumps(p_data).encode("utf-8"),
                    headers={"Content-Type": "application/json"},
                    method="POST"
                )
                with urllib.request.urlopen(req, timeout=12) as response:
                    return json.loads(response.read().decode("utf-8"))
                    
            res_json = await asyncio.to_thread(run_api)
            ai_summary = res_json["candidates"][0]["content"]["parts"][0]["text"].strip()
        except Exception as e:
            print("Gemini API call failed for project report:", e)
            ai_summary = f"No se pudo generar la síntesis automática vía Gemini ({str(e)}). Fallback al resumen estándar."
            
    if not ai_summary:
        ai_summary = f"El proyecto '{project.name}' cuenta con un avance global del {progress_percentage}% ({completed_tasks} de {total_tasks} tareas completadas). "
        if total_tasks == 0:
            ai_summary += "Actualmente no hay tareas planificadas en el tablero Kanban de este proyecto."
        elif progress_percentage == 100:
            ai_summary += "Todas las tareas han sido completadas con éxito de acuerdo a la hoja de ruta establecida."
        else:
            ai_summary += "El proyecto se encuentra en fase de desarrollo activo. Se requiere revisar el cumplimiento de plazos y hitos en el diagrama de Gantt."
            
    return {
        "project_name": project.name,
        "total_tasks": total_tasks,
        "completed_tasks": completed_tasks,
        "progress_percentage": progress_percentage,
        "total_sp": total_sp,
        "completed_sp": completed_sp,
        "sp_progress_percentage": sp_progress_percentage,
        "blocked_count": blocked_count,
        "overdue_count": len(overdue_tasks),
        "close_to_due_count": len(close_to_due_tasks),
        "total_estimated_hours": total_estimated_hours,
        "total_resource_cost": total_resource_cost,
        "completed_resource_cost": completed_resource_cost,
        "ai_summary": ai_summary,
        "sections": sections,
        "ai_enabled": ai_enabled,
        "column_breakdown": column_breakdown,
        "tasks": tasks_data,
        "workload": workload_list,
        "milestones": milestones
    }


@router.post("/projects/{project_id}/roadmap/suggest")
async def suggest_project_roadmap(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    ai_stmt = select(SystemSetting).where(
        SystemSetting.company_id == current_user.company_id
    ).where(SystemSetting.key == "ai_copilot_enabled")
    ai_res = await db.execute(ai_stmt)
    ai_setting = ai_res.scalar_one_or_none()
    ai_enabled = ai_setting.value == "true" if ai_setting else False
    if not ai_enabled:
        raise HTTPException(status_code=400, detail="El asistente de IA no está habilitado.")
        
    key_stmt = select(SystemSetting).where(
        SystemSetting.company_id == current_user.company_id
    ).where(SystemSetting.key == "gemini_api_key")
    key_res = await db.execute(key_stmt)
    key_setting = key_res.scalar_one_or_none()
    api_key = key_setting.value.strip() if key_setting and key_setting.value else None
    if not api_key:
        raise HTTPException(status_code=400, detail="No se ha configurado la API Key de Gemini en el panel de administrador.")
        
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    result = await db.execute(stmt)
    project = result.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    prompt = f"""
Eres un consultor experto en planificación estratégica de proyectos. Genera propuestas realistas para los 6 temas de la Hoja de Ruta del proyecto "{project.name}".
Descripción del proyecto: {project.description or "No provista"}

Debes devolver obligatoriamente un objeto JSON estructurado exactamente con las siguientes 6 claves. No agregues explicaciones fuera del JSON, devuelve únicamente el JSON válido:
{{
  "roadmap_objectives": "Propuesta concisa de objetivos (lista de viñetas, máx 100 palabras)",
  "roadmap_deliverables": "Propuesta de entregables (lista de viñetas, máx 100 palabras)",
  "roadmap_strategy": "Estrategia propuesta para el éxito del proyecto (máx 100 palabras)",
  "roadmap_resources": "Recursos humanos, técnicos y logísticos necesarios (máx 100 palabras)",
  "roadmap_deadlines": "Hitos estimados y plazos de entrega sugeridos (máx 100 palabras)",
  "roadmap_stakeholders": "Partes interesadas a involucrar (máx 100 palabras)"
}}
"""
    try:
        import urllib.request
        import json
        import asyncio
        
        def call_gemini():
            url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={api_key}"
            p_data = {
                "contents": [{"parts": [{"text": prompt}]}],
                "generationConfig": {"responseMimeType": "application/json"}
            }
            req = urllib.request.Request(
                url,
                data=json.dumps(p_data).encode("utf-8"),
                headers={"Content-Type": "application/json"},
                method="POST"
            )
            with urllib.request.urlopen(req, timeout=15) as response:
                return json.loads(response.read().decode("utf-8"))
                
        res_json = await asyncio.to_thread(call_gemini)
        raw_text = res_json["candidates"][0]["content"]["parts"][0]["text"].strip()
        suggestions = json.loads(raw_text)
        return suggestions
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error al llamar a Gemini: {str(e)}")


@router.post("/projects/{project_id}/roadmap/versions", response_model=RoadmapVersionResponse)
async def create_roadmap_version(
    project_id: int,
    payload: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    res = await db.execute(stmt)
    project = res.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    v_name = payload.get("version_name", "").strip()
    if not v_name:
        raise HTTPException(status_code=400, detail="El nombre de la versión es requerido.")
        
    new_ver = ProjectRoadmapVersion(
        project_id=project_id,
        version_name=v_name,
        roadmap_objectives=project.roadmap_objectives,
        roadmap_deliverables=project.roadmap_deliverables,
        roadmap_strategy=project.roadmap_strategy,
        roadmap_resources=project.roadmap_resources,
        roadmap_deadlines=project.roadmap_deadlines,
        roadmap_stakeholders=project.roadmap_stakeholders
    )
    db.add(new_ver)
    await db.commit()
    await db.refresh(new_ver)
    return new_ver


@router.get("/projects/{project_id}/roadmap/versions", response_model=List[RoadmapVersionResponse])
async def list_roadmap_versions(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador", "Visualizador"]))
):
    proj_stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    proj_res = await db.execute(proj_stmt)
    if not proj_res.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    stmt = select(ProjectRoadmapVersion).where(ProjectRoadmapVersion.project_id == project_id).order_by(ProjectRoadmapVersion.created_at.desc())
    res = await db.execute(stmt)
    return res.scalars().all()


@router.post("/projects/{project_id}/roadmap/versions/{version_id}/restore")
async def restore_roadmap_version(
    project_id: int,
    version_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    proj_stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    proj_res = await db.execute(proj_stmt)
    project = proj_res.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    v_stmt = select(ProjectRoadmapVersion).where(ProjectRoadmapVersion.project_id == project_id).where(ProjectRoadmapVersion.id == version_id)
    v_res = await db.execute(v_stmt)
    ver = v_res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión no encontrada")
        
    project.roadmap_objectives = ver.roadmap_objectives
    project.roadmap_deliverables = ver.roadmap_deliverables
    project.roadmap_strategy = ver.roadmap_strategy
    project.roadmap_resources = ver.roadmap_resources
    project.roadmap_deadlines = ver.roadmap_deadlines
    project.roadmap_stakeholders = ver.roadmap_stakeholders
    
    await db.commit()
    return {"detail": "Versión restaurada con éxito"}


@router.delete("/projects/{project_id}/roadmap/versions/{version_id}")
async def delete_roadmap_version(
    project_id: int,
    version_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    stmt = select(ProjectRoadmapVersion).where(ProjectRoadmapVersion.project_id == project_id).where(ProjectRoadmapVersion.id == version_id)
    res = await db.execute(stmt)
    ver = res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión no encontrada")
        
    await db.delete(ver)
    await db.commit()
    return {"detail": "Versión eliminada con éxito"}


@router.put("/projects/{project_id}/roadmap/versions/{version_id}")
async def rename_roadmap_version(
    project_id: int,
    version_id: int,
    payload: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    v_name = payload.get("version_name", "").strip()
    if not v_name:
        raise HTTPException(status_code=400, detail="El nombre de la versión es requerido.")
        
    stmt = select(ProjectRoadmapVersion).where(ProjectRoadmapVersion.project_id == project_id).where(ProjectRoadmapVersion.id == version_id)
    res = await db.execute(stmt)
    ver = res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión no encontrada")
        
    ver.version_name = v_name
    await db.commit()
    return {"detail": "Versión renombrada con éxito"}


@router.post("/projects/{project_id}/report/versions", response_model=ReportVersionResponse)
async def create_report_version(
    project_id: int,
    payload: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    res = await db.execute(stmt)
    if not res.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    v_name = payload.get("version_name", "").strip()
    r_html = payload.get("report_html", "").strip()
    if not v_name:
        raise HTTPException(status_code=400, detail="El nombre de la versión es requerido.")
    if not r_html:
        raise HTTPException(status_code=400, detail="El contenido del informe es requerido.")
        
    new_ver = ProjectReportVersion(
        project_id=project_id,
        version_name=v_name,
        report_html=r_html
    )
    db.add(new_ver)
    await db.commit()
    await db.refresh(new_ver)
    return new_ver


@router.get("/projects/{project_id}/report/versions", response_model=List[ReportVersionResponse])
async def list_report_versions(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador", "Visualizador"]))
):
    proj_stmt = select(Project).where(Project.company_id == current_user.company_id).where(Project.id == project_id)
    proj_res = await db.execute(proj_stmt)
    if not proj_res.scalar_one_or_none():
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    stmt = select(ProjectReportVersion).where(ProjectReportVersion.project_id == project_id).order_by(ProjectReportVersion.created_at.desc())
    res = await db.execute(stmt)
    return res.scalars().all()


@router.get("/projects/{project_id}/report/versions/{version_id}", response_model=ReportVersionResponse)
async def get_report_version(
    project_id: int,
    version_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador", "Visualizador"]))
):
    stmt = select(ProjectReportVersion).where(ProjectReportVersion.project_id == project_id).where(ProjectReportVersion.id == version_id)
    res = await db.execute(stmt)
    ver = res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión de informe no encontrada")
    return ver


@router.put("/projects/{project_id}/report/versions/{version_id}")
async def rename_report_version(
    project_id: int,
    version_id: int,
    payload: dict,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    v_name = payload.get("version_name", "").strip()
    if not v_name:
        raise HTTPException(status_code=400, detail="El nombre de la versión es requerido.")
        
    stmt = select(ProjectReportVersion).where(ProjectReportVersion.project_id == project_id).where(ProjectReportVersion.id == version_id)
    res = await db.execute(stmt)
    ver = res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión no encontrada")
        
    ver.version_name = v_name
    await db.commit()
    return {"detail": "Versión renombrada con éxito"}


@router.delete("/projects/{project_id}/report/versions/{version_id}")
async def delete_report_version(
    project_id: int,
    version_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    stmt = select(ProjectReportVersion).where(ProjectReportVersion.project_id == project_id).where(ProjectReportVersion.id == version_id)
    res = await db.execute(stmt)
    ver = res.scalar_one_or_none()
    if not ver:
        raise HTTPException(status_code=404, detail="Versión no encontrada")
        
    await db.delete(ver)
    await db.commit()
    return {"detail": "Versión eliminada con éxito"}


@router.post("/projects/{project_id}/baseline")
async def save_project_baseline(
    project_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(require_roles(["Administrador", "Project Manager", "Desarrollador"]))
):
    stmt = select(Project).where(Project.id == project_id).options(selectinload(Project.tasks))
    res = await db.execute(stmt)
    project = res.scalar_one_or_none()
    if not project:
        raise HTTPException(status_code=404, detail="Proyecto no encontrado")
        
    for t in project.tasks:
        t.baseline_start_date = t.start_date
        t.baseline_end_date = t.due_date
        
    await db.commit()
    return {"detail": "Línea base del proyecto establecida con éxito"}


