from typing import List

from fastapi import APIRouter, status, HTTPException
from src.core.log_conf import logger
from src.db.repository.media.actorfile import (
    create_new_mediaactorfile,
    delete_mediaactorfile,
)
from src.db.repository.media.file import delete_mediafile, import_mediafile
from src.db.session import SessionDep
from src.schema.media.actor import MediaActorResponse, actor_to_response
from src.schema.media.actorfile import MediaActorFileResponse, actorfile_to_response
from src.schema.media.file import (
    MediaFileModel,
    MediaFileResponse,
    file_to_response,
    file_to_model,
)
from src.db.models.media import MediaFile

router = APIRouter()


@router.get("/update-titles")
def update_titles(db: SessionDep) -> List[MediaFileResponse]:
    """
    Update title for given MediaFile.
    """
    results: list[MediaFileResponse] = []
    files = db.query(MediaFile).filter(MediaFile.review.is_(True)).all()
    for mediafile in files:
        mediafile.update_title()
        db.add(mediafile)
        response = file_to_response(mediafile)
        results.append(response)
    db.commit()
    return results


@router.get("/files", response_model=List[MediaFileResponse])
def get_all_files(
    db: SessionDep, review: bool = False, download: bool = False
) -> List[MediaFileResponse]:
    """
    Get all MediaFiles.
    """
    results: List[MediaFileResponse] = []
    files: List[MediaFile]
    if review:
        files = db.query(MediaFile).filter(MediaFile.review.is_(True)).all()
    elif download:
        files = db.query(MediaFile).filter(MediaFile.should_download.is_(True)).all()
    else:
        files = db.query(MediaFile).all()
    for mediafile in files:
        response = file_to_response(mediafile)
        results.append(response)
    return results


@router.get("/files/{file_id}", response_model=MediaFileResponse)
def get_file(file_id: str, db: SessionDep) -> MediaFileResponse:
    """
    Get MediaFile with given id or return HTTPException.
    """
    mediafile = db.get(MediaFile, file_id)
    if not mediafile:
        raise HTTPException(status_code=404, detail="MediaFile could not be found")
    response = file_to_response(mediafile)
    return response


@router.delete("/files/{file_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_file(file_id: str, db: SessionDep):
    """
    Delete MediaFile by given id.
    """
    mediafile = db.get(MediaFile, file_id)
    if not mediafile:
        raise HTTPException(status_code=404, detail="MediaFile could not be found")
    logger.info("delete MediaFile: %s", file_id)
    actor_files = mediafile.media_actor_files
    logger.info("MediaActorFiles links %s", len(actor_files))
    if len(actor_files) > 0:
        logger.info("delete MediaActor relations first")
        for actor_file in actor_files:
            delete_mediaactorfile(db, actor_file.id)
    delete_mediafile(db, mediafile.id)


@router.get("/files/{file_id}/actors", response_model=list[MediaActorResponse])
def get_file_actors(file_id: str, db: SessionDep) -> list[MediaActorResponse]:
    """
    Get list of Actors for given MediaFile.
    """
    mediafile = db.get(MediaFile, file_id)
    if not mediafile:
        raise HTTPException(status_code=404, detail="MediaFile could not be found")
    actor_files = mediafile.media_actor_files
    logger.info("already known actors: %s", actor_files)
    results: list[MediaActorResponse] = []
    for actor_file in actor_files:
        response = actor_to_response(actor_file.media_actor)
        results.append(response)
    return results


@router.put("/files/{file_id}/actors", response_model=List[MediaActorFileResponse])
def update_file_actors(
    file_id: str, db: SessionDep, actors: List[MediaActorResponse]
) -> List[MediaActorFileResponse]:
    mediafile = db.get(MediaFile, file_id)
    if not mediafile:
        raise HTTPException(status_code=404, detail="MediaFile could not be found")
    actor_files = mediafile.media_actor_files
    logger.info("already known actors: %s", actor_files)
    for actor in actors:
        already_associated = False
        for actor_file in actor_files:
            if actor.id == actor_file.media_actor_id:
                logger.info("alreay associated - do nothing")
                already_associated = True
                break
        if not already_associated:
            create_new_mediaactorfile(db, actor.id, mediafile.id)
    db.refresh(mediafile)
    actor_files = mediafile.media_actor_files
    results: List[MediaActorFileResponse] = []
    for actor_file in actor_files:
        response = actorfile_to_response(actor_file)
        results.append(response)
    return results


@router.put("/files/{file_id}", response_model=MediaFileResponse)
def update_file(
    file_id: str, db: SessionDep, info: MediaFileResponse
) -> MediaFileResponse:
    """
    Update MediaFile with given id and data.
    """
    media_file = db.get(MediaFile, file_id)
    if not media_file:
        raise HTTPException(status_code=404, detail="MediaFile could not be found")
    file_to_model(info, media_file)
    db.add(media_file)
    db.commit()
    mediafile = db.get(MediaFile, file_id)
    if not mediafile:
        raise HTTPException(status_code=404, detail="MediaFile could not be updated")
    response = file_to_response(mediafile)
    return response


@router.post("/files", status_code=status.HTTP_201_CREATED)
def add_file(new_file: MediaFileModel, db: SessionDep) -> MediaFileResponse:
    logger.info("add mediafile %s", new_file)
    try:
        mediaFile: MediaFile = import_mediafile(db, new_file)
    except:
        raise HTTPException(status_code=409, detail="MediaFile duplicate")
    response = file_to_response(mediaFile)
    return response
