from fastapi import APIRouter, Depends, Query, status
from sqlalchemy.orm import Session
from typing import Optional
from utils.utils import get_db
from . import handler
from .schema import (
    JobCreate, JobUpdate, JobResponse, JobDetailResponse, PaginatedJobResponse,
    JobAssignRequest, JobReassignRequest, JobStatusUpdateRequest,
    CommentCreate, CommentUpdate, CommentResponse, PaginatedCommentResponse,
    AttachmentCreate, AttachmentUpdate, AttachmentResponse, PaginatedAttachmentResponse,
    JobhistoryResponse, PaginatedJobhistoryResponse,
    JobtagCreate, JobtagResponse
)

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


@router.post(
    "/",
    response_model=JobResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Create Job",
    description="Creates a new job with title, description, type, priority, status, and assignment details. Validates all foreign key references. Returns 400 if any referenced entity does not exist.",
)
def create_job_route(data: JobCreate, db: Session = Depends(get_db)):
    return handler.create_job(db, data)


@router.get(
    "/",
    response_model=PaginatedJobResponse,
    summary="List Jobs",
    description="Returns a paginated list of jobs. Supports filters for status, priority, assignee, department, and team. Results are ordered by creation date descending.",
)
def list_jobs_route(
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    job_status_id: Optional[str] = Query(None),
    job_priority_id: Optional[str] = Query(None),
    assigned_to_user_id: Optional[str] = Query(None),
    department_id: Optional[str] = Query(None),
    team_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    return handler.list_jobs(
        db,
        limit,
        offset,
        job_status_id=job_status_id,
        job_priority_id=job_priority_id,
        assigned_to_user_id=assigned_to_user_id,
        department_id=department_id,
        team_id=team_id,
    )


@router.get(
    "/{job_id}",
    response_model=JobResponse,
    summary="Get Job",
    description="Returns a single job by ID. Returns 404 if job does not exist.",
)
def get_job_route(job_id: str, db: Session = Depends(get_db)):
    return handler.get_job(db, job_id)


@router.get(
    "/{job_id}/details",
    response_model=JobDetailResponse,
    summary="Get Job Details",
    description="Returns comprehensive job details including all related entities: type, status, priority, users, department, team, parent job, comments, attachments, history, time logs, tags, and checklists with items. All relationships are eagerly loaded. Returns 404 if job does not exist.",
)
def get_job_details_route(job_id: str, db: Session = Depends(get_db)):
    return handler.get_job_details(db, job_id)


@router.patch(
    "/{job_id}",
    response_model=JobResponse,
    summary="Update Job",
    description="Updates job fields. Only provided fields are updated. Validates all foreign key references. Returns 404 if job does not exist, 400 if any referenced entity does not exist.",
)
def update_job_route(job_id: str, data: JobUpdate, db: Session = Depends(get_db)):
    return handler.update_job(db, job_id, data)


@router.delete(
    "/{job_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Job",
    description="Deletes a job by ID. Cascades to all child records. Returns 404 if job does not exist, 409 if deletion is blocked by constraints.",
)
def delete_job_route(job_id: str, db: Session = Depends(get_db)):
    return handler.delete_job(db, job_id)


@router.post(
    "/{job_id}/assign",
    response_model=JobResponse,
    summary="Assign Job To User",
    description="Assigns job to a user. Updates assigned_to_user_id, creates history entry. Returns 404 if job not found, 400 if user does not exist.",
)
def assign_job_route(
    job_id: str,
    data: JobAssignRequest,
    current_user_id: str = Query(..., description="ID of user performing assignment"),
    db: Session = Depends(get_db),
):
    return handler.assign_job(db, job_id, data, current_user_id)


@router.post(
    "/{job_id}/reassign",
    response_model=JobResponse,
    summary="Reassign Job To Different User",
    description="Reassigns job to a different user. Updates assigned_to_user_id, creates history entry, sends notifications to previous and new assignees. Returns 404 if job not found, 400 if new user does not exist.",
)
def reassign_job_route(
    job_id: str,
    data: JobReassignRequest,
    current_user_id: str = Query(..., description="ID of user performing reassignment"),
    db: Session = Depends(get_db),
):
    return handler.reassign_job(db, job_id, data, current_user_id)


@router.post(
    "/{job_id}/status",
    response_model=JobResponse,
    summary="Update Job Status",
    description="Updates job status to a new value. Creates history entry recording status change. Validates status transition. Returns 404 if job not found, 400 if status does not exist.",
)
def update_job_status_route(
    job_id: str,
    data: JobStatusUpdateRequest,
    current_user_id: str = Query(..., description="ID of user performing status update"),
    db: Session = Depends(get_db),
):
    return handler.update_job_status(db, job_id, data, current_user_id)


@router.post(
    "/{job_id}/complete",
    response_model=JobResponse,
    summary="Mark Job As Completed",
    description="Marks job as completed after validating all checklist items are complete. Updates status to Completed, records completion timestamp, creates history entry. Returns 400 if checklist items are incomplete, 404 if job not found.",
)
def complete_job_route(
    job_id: str,
    current_user_id: str = Query(..., description="ID of user completing job"),
    db: Session = Depends(get_db),
):
    return handler.complete_job_with_checklist_validation(db, job_id, current_user_id)


@router.post(
    "/{job_id}/cancel",
    response_model=JobResponse,
    summary="Cancel Job",
    description="Cancels job by updating status to Cancelled. Creates history entry. Stops any active time tracking. Returns 404 if job not found.",
)
def cancel_job_route(
    job_id: str,
    current_user_id: str = Query(..., description="ID of user cancelling job"),
    db: Session = Depends(get_db),
):
    return handler.cancel_job(db, job_id, current_user_id)


@router.post(
    "/{job_id}/reopen",
    response_model=JobResponse,
    summary="Reopen Completed Job",
    description="Reopens a completed job by updating status to In Progress and clearing completion timestamp. Creates history entry. Only Managers or Admins can reopen. Returns 404 if job not found.",
)
def reopen_job_route(
    job_id: str,
    current_user_id: str = Query(..., description="ID of user reopening job"),
    db: Session = Depends(get_db),
):
    return handler.reopen_job(db, job_id, current_user_id)


@router.post(
    "/{job_id}/comments",
    response_model=CommentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Add Comment To Job",
    description="Creates a new comment attached to job. Optionally mentions other users with @username. Returns 400 if job or user does not exist.",
)
def create_comment_route(data: CommentCreate, db: Session = Depends(get_db)):
    return handler.create_comment(db, data)


@router.get(
    "/{job_id}/comments",
    response_model=PaginatedCommentResponse,
    summary="List Job Comments",
    description="Returns paginated list of comments for a specific job. Ordered by creation date descending.",
)
def list_job_comments_route(
    job_id: str,
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    return handler.list_comments(db, limit, offset, job_id=job_id)


@router.post(
    "/{job_id}/attachments",
    response_model=AttachmentResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Upload Attachment To Job",
    description="Uploads a file attachment to job. Validates file type and size (max 10MB). Returns 400 if file size exceeds limit or if job/user does not exist.",
)
def create_attachment_route(data: AttachmentCreate, db: Session = Depends(get_db)):
    return handler.create_attachment(db, data)


@router.get(
    "/{job_id}/attachments",
    response_model=PaginatedAttachmentResponse,
    summary="List Job Attachments",
    description="Returns paginated list of attachments for a specific job. Ordered by creation date descending.",
)
def list_job_attachments_route(
    job_id: str,
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    return handler.list_attachments(db, limit, offset, job_id=job_id)


@router.get(
    "/{job_id}/history",
    response_model=PaginatedJobhistoryResponse,
    summary="Get Job Audit History",
    description="Returns paginated audit trail of all changes and actions performed on job. Includes field changes, status transitions, assignments. Ordered by creation date descending.",
)
def list_job_history_route(
    job_id: str,
    limit: int = Query(20, ge=1),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
):
    return handler.list_job_history(db, limit, offset, job_id=job_id)


@router.post(
    "/{job_id}/tags",
    response_model=JobtagResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Add Tag To Job",
    description="Associates a tag with a job. Returns 409 if tag already associated with job, 400 if job or tag does not exist.",
)
def create_jobtag_route(data: JobtagCreate, db: Session = Depends(get_db)):
    return handler.create_jobtag(db, data)


@router.delete(
    "/tags/{jobtag_id}",
    status_code=status.HTTP_200_OK,
    summary="Remove Tag From Job",
    description="Removes tag association from job. Returns 404 if job tag relationship does not exist.",
)
def delete_jobtag_route(jobtag_id: str, db: Session = Depends(get_db)):
    return handler.delete_jobtag(db, jobtag_id)


@router.get(
    "/comments/{comment_id}",
    response_model=CommentResponse,
    summary="Get Comment",
    description="Returns a single comment by ID. Returns 404 if comment does not exist.",
)
def get_comment_route(comment_id: str, db: Session = Depends(get_db)):
    return handler.get_comment(db, comment_id)


@router.patch(
    "/comments/{comment_id}",
    response_model=CommentResponse,
    summary="Update Comment",
    description="Updates comment content. Returns 404 if comment does not exist.",
)
def update_comment_route(comment_id: str, data: CommentUpdate, db: Session = Depends(get_db)):
    return handler.update_comment(db, comment_id, data)


@router.delete(
    "/comments/{comment_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Comment",
    description="Deletes a comment by ID. Returns 404 if comment does not exist.",
)
def delete_comment_route(comment_id: str, db: Session = Depends(get_db)):
    return handler.delete_comment(db, comment_id)


@router.get(
    "/attachments/{attachment_id}",
    response_model=AttachmentResponse,
    summary="Get Attachment",
    description="Returns a single attachment by ID. Returns 404 if attachment does not exist.",
)
def get_attachment_route(attachment_id: str, db: Session = Depends(get_db)):
    return handler.get_attachment(db, attachment_id)


@router.patch(
    "/attachments/{attachment_id}",
    response_model=AttachmentResponse,
    summary="Update Attachment",
    description="Updates attachment metadata. Returns 404 if attachment does not exist.",
)
def update_attachment_route(attachment_id: str, data: AttachmentUpdate, db: Session = Depends(get_db)):
    return handler.update_attachment(db, attachment_id, data)


@router.delete(
    "/attachments/{attachment_id}",
    status_code=status.HTTP_200_OK,
    summary="Delete Attachment",
    description="Deletes an attachment by ID. Returns 404 if attachment does not exist.",
)
def delete_attachment_route(attachment_id: str, db: Session = Depends(get_db)):
    return handler.delete_attachment(db, attachment_id)


@router.get(
    "/history/{history_id}",
    response_model=JobhistoryResponse,
    summary="Get Job History Entry",
    description="Returns a single job history entry by ID. Returns 404 if history entry does not exist.",
)
def get_jobhistory_route(history_id: str, db: Session = Depends(get_db)):
    return handler.get_jobhistory(db, history_id)