"""
Job submission and status routes.

Routes for submitting jobs and querying job status.
Delegates all logic to service layer.
"""

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field

from ..services.job_status import JobStatusService
from ..services.job_submission import JobSubmissionService

router = APIRouter(prefix="/api/v1/jobs", tags=["jobs"])


# Request/Response Models
class JobSubmitRequest(BaseModel):
    """
    Job submission request body.

    Supports two config workflows:
    1. Inline: Provide config_content (uploaded automatically)
    2. Reference: Provide config_s3_path (existing S3 object)
    """

    job_type: str = Field(..., description="Type of job (k8s, generate, etc.)")
    dataset_name: str = Field(..., description="Dataset identifier")
    user_id: str = Field(..., description="User identifier")
    config_content: str | None = Field(
        None, description="Inline config content (YAML string)"
    )
    config_s3_path: str | None = Field(None, description="S3 path to existing config")
    config_type: str = Field(default="file", description="'file' or 'directory'")
    description: str = Field(default="", description="Job description")
    recreate_connections: bool = Field(default=False, description="Recreate CloudZero connections (upload stage only)")


class JobSubmitResponse(BaseModel):
    """Job submission response."""

    job_id: str
    status: str
    message: str


class JobStatusResponse(BaseModel):
    """Job status response."""

    job_id: str
    job_type: str
    dataset_name: str
    status: str
    created_at: str
    started_at: str | None = None
    completed_at: str | None = None
    result: dict | None = None
    error: str | None = None


# Dependency injection placeholders (will be set in main.py)
_job_submission_service: JobSubmissionService | None = None
_job_status_service: JobStatusService | None = None


def get_job_submission_service() -> JobSubmissionService:
    """Get job submission service instance."""
    if _job_submission_service is None:
        raise RuntimeError("Job submission service not initialized")
    return _job_submission_service


def get_job_status_service() -> JobStatusService:
    """Get job status service instance."""
    if _job_status_service is None:
        raise RuntimeError("Job status service not initialized")
    return _job_status_service


def init_services(
    submission_service: JobSubmissionService,
    status_service: JobStatusService,
) -> None:
    """
    Initialize service dependencies.

    Called from main.py during app startup.
    """
    global _job_submission_service, _job_status_service
    _job_submission_service = submission_service
    _job_status_service = status_service


# Routes
@router.post("/generate", response_model=JobSubmitResponse)
async def submit_generate_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit generate job.

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="generate",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Generate job submitted successfully: {job_id}",
        )
    except ValueError as e:
        # Config validation errors (neither/both provided)
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/k8s", response_model=JobSubmitResponse)
async def submit_k8s_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit k8s allocation job.

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="k8s",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"K8s job submitted successfully: {job_id}",
        )
    except ValueError as e:
        # Config validation errors (neither/both provided)
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.get("/{job_id}/status", response_model=JobStatusResponse)
async def get_job_status(
    job_id: str,
    service: JobStatusService = Depends(get_job_status_service),
) -> JobStatusResponse:
    """
    Get current job status.

    Returns job metadata and processing status.
    """
    try:
        status = service.get_job_status(job_id)

        if status is None:
            raise HTTPException(
                status_code=404, detail=f"Job not found: {job_id}"
            )

        return JobStatusResponse(**status)
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/metadata", response_model=JobSubmitResponse)
async def submit_metadata_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit metadata allocation job.

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="metadata",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Metadata job submitted successfully: {job_id}",
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/usage", response_model=JobSubmitResponse)
async def submit_usage_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit usage allocation job.

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="usage",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Usage job submitted successfully: {job_id}",
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/discount", response_model=JobSubmitResponse)
async def submit_discount_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit discount allocation job.

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="discount",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Discount job submitted successfully: {job_id}",
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/upload", response_model=JobSubmitResponse)
async def submit_upload_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit upload job.

    Uploads generated datasets to CloudZero organizations.
    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="upload_generated",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
            recreate_connections=request.recreate_connections,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Upload job submitted successfully: {job_id}",
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.post("/time_shift", response_model=JobSubmitResponse)
async def submit_time_shift_job(
    request: JobSubmitRequest,
    service: JobSubmissionService = Depends(get_job_submission_service),
) -> JobSubmitResponse:
    """
    Submit time-shift job.

    Transforms existing billing drops to new time periods via:
    1. Reading source CSV.gz files from S3
    2. Transforming timestamps in memory (Polars)
    3. Writing to target month folders in S3

    Supports inline config or S3 reference.
    Job will be queued for processing by worker.
    """
    try:
        job_id = service.submit_job(
            job_type="time_shift",
            dataset_name=request.dataset_name,
            user_id=request.user_id,
            config_content=request.config_content,
            config_s3_path=request.config_s3_path,
            config_type=request.config_type,
            description=request.description,
        )

        return JobSubmitResponse(
            job_id=job_id,
            status="queued",
            message=f"Time-shift job submitted successfully: {job_id}",
        )
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e)) from e
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e


@router.get("/user/{user_id}")
async def get_user_jobs(
    user_id: str,
    limit: int = 10,
    service: JobStatusService = Depends(get_job_status_service),
) -> list[dict]:
    """
    Get recent jobs for a user.

    Returns list of job status summaries.
    """
    try:
        return service.get_user_jobs(user_id, limit)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e)) from e
