from pathlib import Path
import subprocess
import tempfile

import requests
from django.db import transaction

from apps.assets.models import Asset, AssetFile
from apps.assets.storage import TosStorage
from apps.projects.models import ExportJob


def _download_asset_primary_file(asset, target_path: Path) -> None:
    primary = asset.files.filter(is_primary=True).first() or asset.files.first()
    if primary is None:
        raise ValueError(f"asset {asset.id} has no file")
    url = TosStorage().presigned_get_url(object_key=primary.object_key, expires_in=3600)
    response = requests.get(url, timeout=180)
    response.raise_for_status()
    target_path.write_bytes(response.content)


def run_export_job(export_job_id: str) -> ExportJob:
    export_job = ExportJob.objects.select_related("timeline", "timeline__project").get(id=export_job_id)
    timeline = export_job.timeline
    project = timeline.project
    clips = list(timeline.clips.select_related("asset").order_by("sort_order"))
    if not clips:
        raise ValueError("timeline has no clips")

    export_job.status = ExportJob.Status.RUNNING
    export_job.progress = 10
    export_job.save(update_fields=["status", "progress", "updated_at"])

    with tempfile.TemporaryDirectory(prefix="airshelf-export-") as tmp_dir:
        tmp = Path(tmp_dir)
        concat_file = tmp / "concat.txt"
        downloaded_files: list[Path] = []
        for index, clip in enumerate(clips):
            clip_path = tmp / f"clip-{index}.mp4"
            _download_asset_primary_file(clip.asset, clip_path)
            downloaded_files.append(clip_path)
        concat_file.write_text(
            "\n".join(f"file '{path.as_posix()}'" for path in downloaded_files),
            encoding="utf-8",
        )
        output_path = tmp / "output.mp4"
        command = [
            "ffmpeg",
            "-y",
            "-f",
            "concat",
            "-safe",
            "0",
            "-i",
            str(concat_file),
            "-vf",
            "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2",
            "-r",
            "30",
            "-c:v",
            "libx264",
            "-pix_fmt",
            "yuv420p",
            "-c:a",
            "aac",
            "-movflags",
            "+faststart",
            str(output_path),
        ]
        subprocess.run(command, check=True, capture_output=True)
        export_job.progress = 85
        export_job.save(update_fields=["progress", "updated_at"])

        with output_path.open("rb") as fileobj:
            asset_id = export_job.id
            object_key = f"teams/{project.team_id}/projects/{project.id}/exports/{asset_id}.mp4"
            stored = TosStorage().upload_fileobj(fileobj=fileobj, object_key=object_key, content_type="video/mp4")

        with transaction.atomic():
            asset = Asset.objects.create(
                team=project.team,
                created_by=project.created_by,
                name=f"{project.name}-final.mp4",
                asset_type=Asset.Type.VIDEO,
                source=Asset.Source.EXPORTED,
                category=Asset.Category.FINAL_VIDEO,
            )
            AssetFile.objects.create(
                asset=asset,
                object_key=stored.object_key,
                bucket=stored.bucket,
                content_type=stored.content_type,
                size_bytes=stored.size_bytes,
                is_primary=True,
            )
            export_job.output_asset = asset
            export_job.status = ExportJob.Status.SUCCEEDED
            export_job.progress = 100
            export_job.error_message = ""
            export_job.save(update_fields=["output_asset", "status", "progress", "error_message", "updated_at"])
            project.status = project.Status.COMPLETED
            project.save(update_fields=["status", "updated_at"])
    return export_job

