from fastapi import APIRouter, Depends, HTTPException
from typing import Any, Dict, Optional
from datetime import datetime
from loguru import logger

from sqlalchemy.orm import Session

from middleware.auth_middleware import get_current_user
from services.database import get_db
from services.today_workflow_service import coerce_dependencies, get_or_create_daily_workflow_plan, update_task_status
from models.daily_workflow_models import DailyWorkflowPlan, DailyWorkflowTask
import asyncio
from services.intelligence.txtai_service import TxtaiIntelligenceService


router = APIRouter(prefix="/api/today-workflow", tags=["Today Workflow"])

async def _index_tasks_to_sif(user_id: str, date: str, tasks: list[dict], label: str):
    svc = TxtaiIntelligenceService(user_id)
    items = []
    for t in tasks:
        task_id = t.get("id")
        pillar_id = t.get("pillarId")
        status = t.get("status")
        title = t.get("title")
        description = t.get("description")
        text = f"[{pillar_id}] {title}\n{description}\nstatus={status}"
        metadata = {
            "type": "daily_workflow_task",
            "date": date,
            "label": label,
            "pillar_id": pillar_id,
            "status": status,
            "implemented": status == "completed",
            "dismissed": status == "skipped",
            "task_id": task_id,
        }
        items.append((f"{label}_task:{user_id}:{date}:{task_id}", text, metadata))
    try:
        await svc.index_content(items)
    except Exception:
        return


def _build_provenance_summary(plan: DailyWorkflowPlan, tasks: list[DailyWorkflowTask]) -> Dict[str, Any]:
    source_counts: Dict[str, int] = {}
    for task in tasks:
        metadata = task.metadata_json if isinstance(task.metadata_json, dict) else {}
        source = metadata.get("source") if metadata.get("source") in {"agent_committee", "llm_generation", "llm_pillar_backfill", "controlled_fallback"} else "llm_generation"
        source_counts[source] = source_counts.get(source, 0) + 1

    generation_mode = plan.generation_mode if plan.generation_mode in {"agent_committee", "llm_generation", "llm_pillar_backfill", "controlled_fallback"} else "llm_generation"

    return {
        "generationMode": generation_mode,
        "committeeAgentCount": int(plan.committee_agent_count or 0),
        "fallbackUsed": bool(plan.fallback_used),
        "taskSourceBreakdown": source_counts,
    }

@router.get("")
async def get_today_workflow(
    date: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    from starlette.concurrency import run_in_threadpool
    user_id = str(current_user.get("id"))
    plan, created = await get_or_create_daily_workflow_plan(db, user_id, date=date)

    def _fetch_tasks():
        return (
            db.query(DailyWorkflowTask)
            .filter(DailyWorkflowTask.plan_id == plan.id, DailyWorkflowTask.user_id == user_id)
            .order_by(DailyWorkflowTask.created_at.asc())
            .all()
        )

    tasks = await run_in_threadpool(_fetch_tasks)
    provenance_summary = _build_provenance_summary(plan, tasks)

    def _normalize_legacy_dependencies(task_rows):
        rows_updated = False
        for row in task_rows:
            normalized_dependencies = coerce_dependencies(row.dependencies)
            if row.dependencies != normalized_dependencies:
                row.dependencies = normalized_dependencies
                db.add(row)
                rows_updated = True
        if rows_updated:
            db.commit()

    await run_in_threadpool(_normalize_legacy_dependencies, tasks)

    response_tasks = []
    for t in tasks:
        response_tasks.append(
            {
                "id": str(t.id),
                "pillarId": t.pillar_id,
                "title": t.title,
                "description": t.description,
                "status": "skipped" if t.status == "dismissed" else t.status,
                "priority": t.priority,
                "estimatedTime": t.estimated_time,
                "dependencies": coerce_dependencies(t.dependencies),
                "actionUrl": t.action_url,
                "actionType": t.action_type,
                "metadata": t.metadata_json or {},
                "enabled": bool(t.enabled),
            }
        )

    total = len(response_tasks)
    completed = len([t for t in response_tasks if t["status"] in ("completed", "skipped")])
    current_index = 0
    for i, task in enumerate(response_tasks):
        if task["status"] not in ("completed", "skipped"):
            current_index = i
            break
        current_index = i

    workflow_status = "not_started"
    if completed > 0 and completed < total:
        workflow_status = "in_progress"
    elif total > 0 and completed == total:
        workflow_status = "completed"

    total_estimated = int(sum(int(t.get("estimatedTime") or 0) for t in response_tasks))

    if created:
        asyncio.create_task(_index_tasks_to_sif(user_id, plan.date, response_tasks, label="today"))
        try:
            from datetime import date as date_type, timedelta

            y_str = (date_type.fromisoformat(plan.date) - timedelta(days=1)).isoformat()
            
            def _fetch_yesterday():
                y_plan = (
                    db.query(DailyWorkflowPlan)
                    .filter(DailyWorkflowPlan.user_id == user_id, DailyWorkflowPlan.date == y_str)
                    .first()
                )
                if y_plan:
                    y_tasks = (
                        db.query(DailyWorkflowTask)
                        .filter(DailyWorkflowTask.plan_id == y_plan.id, DailyWorkflowTask.user_id == user_id)
                        .order_by(DailyWorkflowTask.created_at.asc())
                        .all()
                    )
                    return y_tasks
                return []

            y_tasks = await run_in_threadpool(_fetch_yesterday)
            
            if y_tasks:
                y_response = []
                for t in y_tasks:
                    y_response.append(
                        {
                            "id": str(t.id),
                            "pillarId": t.pillar_id,
                            "title": t.title,
                            "description": t.description,
                            "status": "skipped" if t.status == "dismissed" else t.status,
                        }
                    )
                asyncio.create_task(_index_tasks_to_sif(user_id, y_str, y_response, label="yesterday"))
        except Exception:
            pass

    return {
        "success": True,
        "data": {
            "workflow": {
                "id": f"daily-{user_id}-{plan.date}",
                "date": plan.date,
                "userId": user_id,
                "tasks": response_tasks,
                "currentTaskIndex": current_index,
                "completedTasks": completed,
                "totalTasks": total,
                "workflowStatus": workflow_status,
                "totalEstimatedTime": total_estimated,
                "actualTimeSpent": 0,
                "provenanceSummary": provenance_summary,
            },
            "plan": {
                "id": plan.id,
                "date": plan.date,
                "source": plan.source,
                "created_at": plan.created_at.isoformat() if plan.created_at else None,
                "updated_at": plan.updated_at.isoformat() if plan.updated_at else None,
                "generation_mode": plan.generation_mode,
                "committee_agent_count": plan.committee_agent_count,
                "fallback_used": plan.fallback_used,
                "provenance_summary": provenance_summary,
            },
        },
        "timestamp": datetime.utcnow().isoformat(),
        "user_id": user_id,
    }


from services.task_memory_service import TaskMemoryService

@router.post("/tasks/{task_id}/status")
async def set_task_status(
    task_id: int,
    body: Dict[str, Any],
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> Dict[str, Any]:
    user_id = str(current_user.get("id"))
    status = body.get("status")
    if not status:
        raise HTTPException(status_code=400, detail="status is required")
    completion_notes = body.get("completion_notes")

    task = update_task_status(db, user_id, task_id, status=status, completion_notes=completion_notes)
    if not task:
        raise HTTPException(status_code=404, detail="Task not found")

    # Record outcome in memory for self-learning
    try:
        memory = TaskMemoryService(user_id, db)
        await memory.record_task_outcome(
            task, 
            feedback_score=1 if status == "completed" else -1 if status in ("dismissed", "skipped") else 0,
            feedback_text=completion_notes
        )
    except Exception as e:
        logger.warning(
            "Task memory outcome recording failed for user_id={} task_id={} error_class={} error_message={}",
            user_id,
            task_id,
            type(e).__name__,
            str(e),
        )

    plan_for_date = db.query(DailyWorkflowPlan).filter(DailyWorkflowPlan.id == task.plan_id).first()
    plan_date = plan_for_date.date if plan_for_date and plan_for_date.date else ""
    task_payload = {
        "id": str(task.id),
        "pillarId": task.pillar_id,
        "title": task.title,
        "description": task.description,
        "status": "skipped" if task.status in ("dismissed", "skipped") else task.status,
    }
    asyncio.create_task(_index_tasks_to_sif(user_id, plan_date, [task_payload], label="today"))

    return {
        "success": True,
        "data": {
            "task": {
                "id": str(task.id),
                "pillarId": task.pillar_id,
                "status": "skipped" if task.status in ("dismissed", "skipped") else task.status,
                "decided_at": task.decided_at.isoformat() if task.decided_at else None,
            }
        },
        "timestamp": datetime.utcnow().isoformat(),
        "user_id": user_id,
    }
