import dataclasses
from typing import Annotated

from fastapi import HTTPException, Request
from fastapi.params import Form
from fastapi.responses import HTMLResponse
from folkugat_web.api import router
from folkugat_web.fragments import temes
from folkugat_web.fragments.tema import scores as scores_fragments
from folkugat_web.services import auth, files, lilypond
from folkugat_web.services.temes import properties as properties_service
from folkugat_web.services.temes import query as temes_q
from folkugat_web.services.temes import scores as scores_service
from folkugat_web.utils import FnChain


@router.get("/api/tema/{tema_id}/score/{score_id}")
def score(request: Request, logged_in: auth.LoggedIn, tema_id: int, score_id: int):
    score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
    if not score:
        raise HTTPException(status_code=404, detail="Could not find lyric!")
    return scores_fragments.score(request=request, logged_in=logged_in, score=score)


@router.put("/api/tema/{tema_id}/score/{score_id}")
async def set_score(
    request: Request,
    logged_in: auth.RequireLogin,
    tema_id: int,
    score_id: int,
    title: Annotated[str, Form()],
    source: Annotated[str, Form()],
):
    source = source.strip()
    score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
    if not score:
        raise HTTPException(status_code=404, detail="Could not find lyric!")

    full_source = scores_service.build_single_tune_full_source(tema_id=tema_id, source=source)
    pdf_filename = files.create_tema_filename(tema_id=tema_id)
    pdf_filename, errors = await lilypond.render(source=full_source, fmt="pdf", output_filename=pdf_filename)
    if errors:
        new_score = dataclasses.replace(
            score,
            source=source,
            title=title,
            errors=errors,
        )
    else:
        png_filename = files.create_tema_filename(tema_id=tema_id)
        png_filename, errors = await lilypond.render(source=full_source, fmt="png", output_filename=png_filename)
        new_score = dataclasses.replace(
            score,
            source=source,
            title=title,
            pdf_url=files.get_db_file_path(pdf_filename) if pdf_filename else None,
            img_url=files.get_db_file_path(png_filename) if png_filename else None,
            errors=errors,
        )
    scores_service.update_score(score=new_score)
    files.clean_orphan_files()
    return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)


@router.post("/api/tema/{tema_id}/score")
def add_score(
    request: Request,
    logged_in: auth.RequireLogin,
    tema_id: int,
):
    score = scores_service.create_score(tema_id=tema_id)
    return scores_fragments.score_editor(
        request=request,
        logged_in=logged_in,
        score=score,
    )


@router.delete("/api/tema/{tema_id}/score/{score_id}")
def delete_score(request: Request, logged_in: auth.RequireLogin, tema_id: int, score_id: int):
    scores_service.delete_score(score_id=score_id, tema_id=tema_id)
    files.clean_orphan_files()
    return HTMLResponse()


@router.get("/api/tema/{tema_id}/editor/score/{score_id}")
def score_editor(
    request: Request,
    logged_in: auth.RequireLogin,
    tema_id: int,
    score_id: int,
):
    score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
    if not score:
        raise HTTPException(status_code=404, detail="Could not find lyric!")
    return scores_fragments.score_editor(
        request=request,
        logged_in=logged_in,
        score=score,
    )


@router.post("/api/tema/{tema_id}/editor/score/{score_id}/render")
async def render(
    request: Request,
    _: auth.RequireLogin,
    tema_id: int,
    score_id: int,
    source: Annotated[str, Form()],
):
    full_source = scores_service.build_single_tune_full_source(tema_id=tema_id, source=source)
    output_filename, errors = await lilypond.render(source=full_source, fmt="png")
    if output_filename:
        score_render_url = files.get_db_file_path(output_filename)
        return temes.score_render(request=request, score_id=score_id, score_render_url=score_render_url)
    else:
        return temes.score_render(request=request, score_id=score_id, errors=errors)


@router.put("/api/tema/{tema_id}/score/{score_id}/show")
async def show_score(
    request: Request,
    logged_in: auth.RequireLogin,
    tema_id: int,
    score_id: int,
):
    score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
    if not score:
        raise HTTPException(status_code=404, detail="Could not find lyric!")
    new_score = dataclasses.replace(score, hidden=False)
    scores_service.update_score(score=new_score)
    return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)


@router.put("/api/tema/{tema_id}/score/{score_id}/hide")
async def hide_score(
    request: Request,
    logged_in: auth.RequireLogin,
    tema_id: int,
    score_id: int,
):
    score = scores_service.get_score_by_id(score_id=score_id, tema_id=tema_id)
    if not score:
        raise HTTPException(status_code=404, detail="Could not find lyric!")
    new_score = dataclasses.replace(score, hidden=True)
    scores_service.update_score(score=new_score)
    return scores_fragments.score(request=request, logged_in=logged_in, score=new_score)
