"""
Question Bank Competency Evaluation — FastAPI Layer
===================================================

Enterprise-grade HTTP API for the LMS Question Bank Competency feature.

  Phase 1 — TRAIN:
      1. POST /train/{client_id}/start
      2. POST /train/{client_id}/question-bank-batch
      3. POST /train/{client_id}/finalize-questions

  Phase 2 — REPORT:
      GET  /report/{client_id}                         → Full competency result (for cron/admin)
      GET  /report/status/{client_id}                  → Training status check

All data is client-isolated — no cross-contamination between organisations.
"""

import os
import logging
from typing import Any, Dict, List, Optional

from fastapi import FastAPI, HTTPException, Path, status
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field

# ---------------------------------------------------------------------------
# Import processor module
# ---------------------------------------------------------------------------
try:
    from assessment_report_analysis_processor import (
        get_training_status,
        get_question_bank_result,
        list_all_clients,
        delete_client_data,
        initialize_client_store,
        accumulate_question_bank,
        finalize_question_bank,
        mark_training_failed,
        TrainingStatus,
    )
except ImportError:
    import sys
    sys.path.append(os.path.dirname(os.path.abspath(__file__)))
    from assessment_report_analysis_processor import (
        get_training_status,
        get_question_bank_result,
        list_all_clients,
        delete_client_data,
        initialize_client_store,
        accumulate_question_bank,
        finalize_question_bank,
        mark_training_failed,
        TrainingStatus,
    )

# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
)
VERSION = "3.0.0-LIGHT"
logger = logging.getLogger("assessment_report_api")


# ===========================================================================
# SECTION 1 — INPUT Pydantic Models
# ===========================================================================

class QuestionBankItem(BaseModel):
    id:             str           = Field(...,  description="Unique encrypted question identifier.")
    questionText:   str           = Field(...,  description="Full question content.")
    questionType:   int           = Field(...,  description="Question format type.")
    categoryName:   Optional[str] = Field("",   description="Category of the question for classification.")
    questionOption: Optional[str] = Field("",   description="Available options for the question.")
    class Config:
        extra = "ignore"


class QuestionBankBatchRequest(BaseModel):
    """Payload for a batch of question bank data."""
    question_bank: List[QuestionBankItem] = Field(..., description="Batch of question bank items.")
    class Config:
        extra = "ignore"


# ===========================================================================
# SECTION 2 — RESPONSE Models
# ===========================================================================

class StatusResponse(BaseModel):
    status:    bool           = Field(..., description="True if client exists.")
    message:   str            = Field(..., description="Status message.")
    client_id: int            = Field(..., description="The client ID.")
    training:  Dict[str, Any] = Field(..., description="Training metadata.")


# ===========================================================================
# SECTION 3 — FastAPI Application
# ===========================================================================

app = FastAPI(
    title="Question Bank Competency API",
    description=(
        "## LMS Question Bank Competency API\n\n"
        "Streamlined competency mapping for question banks.\n\n"
        "### Workflow\n\n"
        "1. `/train/{id}/start` — Initialize\n"
        "2. `/train/{id}/question-bank-batch` — Send data\n"
        "3. `/train/{id}/finalize-questions` — Classify & Save\n"
        "4. `/report/{id}` — Get Results (used by PHP cron)"
    ),
    version=VERSION,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# ===========================================================================
# SECTION 4 — TRAINING ENDPOINTS
# ===========================================================================

@app.post(
    "/train/{client_id}/start",
    summary="Initialize question bank training",
    tags=["Training"],
)
async def start_training_endpoint(
    client_id: int = Path(..., ge=1, description="Unique integer client ID."),
):
    """Initializes the pipeline for question bank training."""
    logger.info(f"POST /train/{client_id}/start")
    try:
        meta = initialize_client_store(client_id)
        return {
            "status":    True,
            "message":   f"Question bank training initialized for client {client_id}.",
            "client_id": client_id,
            "training":  meta
        }
    except Exception as exc:
        logger.exception(f"Failed to initialize store for client {client_id}: {exc}")
        raise HTTPException(status_code=500, detail=str(exc))


@app.post(
    "/train/{client_id}/question-bank-batch",
    summary="Accumulate a batch of question bank data",
    tags=["Training"],
)
async def question_bank_batch(
    payload: QuestionBankBatchRequest,
    client_id: int = Path(..., ge=1),
):
    """Accumulates question bank data in batches."""
    logger.info(f"POST /train/{client_id}/question-bank-batch | count={len(payload.question_bank)}")
    try:
        q_bank = [q.model_dump() for q in payload.question_bank]
        result = accumulate_question_bank(client_id, q_bank)
        return {
            "status": True,
            "message": f"Batch accumulated. Total: {result.get('total_questions')}",
            "client_id": client_id
        }
    except Exception as exc:
        logger.exception(f"Failed to accumulate for client {client_id}: {exc}")
        raise HTTPException(status_code=500, detail=str(exc))


@app.post(
    "/train/{client_id}/finalize-questions",
    summary="Finalize question classification",
    tags=["Training"],
)
async def finalize_questions_endpoint(
    client_id: int = Path(..., ge=1),
):
    """Processes all accumulated questions and generates competency mapping."""
    logger.info(f"POST /train/{client_id}/finalize-questions")
    try:
        result = finalize_question_bank(client_id)
        if "error" in result:
            raise HTTPException(status_code=400, detail=result["error"])
        return {
            "status": True,
            "message": f"Training completed for client {client_id}.",
            "client_id": client_id,
            "total_questions": result.get("total_questions", 0)
        }
    except Exception as exc:
        logger.exception(f"Failed to finalize for client {client_id}: {exc}")
        raise HTTPException(status_code=500, detail=str(exc))


# ===========================================================================
# SECTION 5 — REPORT ENDPOINTS
# ===========================================================================

@app.get(
    "/report/{client_id}",
    summary="Retrieve full question competency result (used by PHP cron)",
    tags=["Report"],
)
async def get_report(
    client_id: int = Path(..., ge=1),
):
    """
    Returns the question_bank_result.json for the client.
    Used by the PHP cron job (trainUserAttemptData) to get the
    competency mapping for all questions.
    Returns:
      - status: bool
      - result.questions: {question_id: {competency, ...}}
      - result.competency_summary: {competency_name: count}
      - result.total_questions: int
    """
    logger.info(f"GET /report/{client_id}")

    status_meta = get_training_status(client_id)
    if not status_meta:
        raise HTTPException(status_code=404, detail="Client not found.")

    if status_meta.get("status") != TrainingStatus.COMPLETED:
        return {
            "status": False,
            "message": f"Training status: {status_meta.get('status')}",
            "client_id": client_id,
            "training": status_meta
        }

    result = get_question_bank_result(client_id)
    if not result:
        raise HTTPException(status_code=500, detail="Result file missing.")

    return {
        "status": True,
        "message": "Results retrieved.",
        "client_id": client_id,
        "result": result
    }


@app.get(
    "/report/status/{client_id}",
    response_model=StatusResponse,
    summary="Check training status",
    tags=["Report"],
)
async def check_status(
    client_id: int = Path(..., ge=1),
):
    meta = get_training_status(client_id)
    if meta is None:
        raise HTTPException(status_code=404, detail="Client not found.")
    return StatusResponse(
        status=True,
        message=f"Status: {meta.get('status')}",
        client_id=client_id,
        training=meta,
    )


# ===========================================================================
# SECTION 6 — MANAGEMENT ENDPOINTS
# ===========================================================================

@app.get("/clients", summary="List all clients", tags=["Management"])
async def list_clients():
    return {"status": True, "clients": list_all_clients()}


@app.delete("/client/{client_id}", summary="Delete client data", tags=["Management"])
async def delete_client(client_id: int = Path(..., ge=1)):
    try:
        if delete_client_data(client_id):
            return {"status": True, "message": "Deleted."}
        raise HTTPException(status_code=404, detail="Not found.")
    except RuntimeError as exc:
        raise HTTPException(status_code=409, detail=str(exc))


@app.get("/health", summary="Health check", tags=["System"])
async def health_check():
    return {"status": "ok", "version": VERSION}
