"""
backfill_media_by_bot_id.py
----------------------------
Manually fetches the audio and video for a specific meeting from Recall AI
and uploads them to S3, updating the database exactly as the normal pipeline does.

Use this when the server crashed mid-processing and the recording row in the
database has null audio_download_url / video_download_url.

Usage:
    # By bot ID
    python scripts/backfill_media_by_bot_id.py --bot-id "2d9750c1-3777-4cf8-a439-7ca57077a908"

    # By meeting ID
    python scripts/backfill_media_by_bot_id.py --meeting-id 123

    # Force re-upload even if S3 URLs already exist
    python scripts/backfill_media_by_bot_id.py --bot-id "..." --force

Docker:
    docker exec -it iih_ai-notemaker-app python /app/scripts/backfill_media_by_bot_id.py --bot-id "YOUR_BOT_ID"
"""
import argparse
import logging
import sys
from pathlib import Path

import requests

PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from app import crud
from app.database import SessionLocal
from app.services import recall_service

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
)
logger = logging.getLogger(__name__)


def backfill_media(meeting_id: int = None, bot_id: str = None, force: bool = False) -> int:
    db = SessionLocal()
    try:
        # ── Step 1: Resolve the meeting ─────────────────────────────────────
        if bot_id:
            meeting = db.query(crud.Meeting).filter(crud.Meeting.recall_bot_id == bot_id).first()
            if not meeting:
                logger.error("No meeting found in the database for bot ID: %s", bot_id)
                return 1
            logger.info("Resolved bot ID %s → meeting ID %s ('%s')", bot_id, meeting.id, meeting.title)
            meeting_id = meeting.id
        else:
            meeting = crud.get_meeting_by_id(db, meeting_id)
            if not meeting:
                logger.error("No meeting found in the database for meeting ID: %s", meeting_id)
                return 1
            logger.info("Found meeting ID %s ('%s')", meeting.id, meeting.title)

        if not meeting.recall_bot_id:
            logger.error("Meeting %s has no recall_bot_id in the database. Cannot fetch media.", meeting.id)
            return 1

        # ── Step 2: Check current recording state ───────────────────────────
        recording = crud.get_recording_by_meeting(db, meeting_id)

        if recording:
            has_audio = bool(recording.audio_download_url)
            has_video = bool(recording.video_download_url)

            if has_audio and has_video and not force:
                logger.info(
                    "Meeting %s already has both audio and video in the database. "
                    "Use --force to re-upload anyway. Skipping.",
                    meeting_id,
                )
                logger.info("  Audio: %s", recording.audio_download_url)
                logger.info("  Video: %s", recording.video_download_url)
                return 0

            if has_audio and not force:
                logger.info("Meeting %s already has audio. Only video will be re-fetched.", meeting_id)
            if has_video and not force:
                logger.info("Meeting %s already has video. Only audio will be re-fetched.", meeting_id)
        else:
            logger.info("No recording row exists yet for meeting %s. A new one will be created.", meeting_id)

        # ── Step 3: Fetch the latest bot data from Recall AI ────────────────
        logger.info("Fetching bot data from Recall AI for bot ID: %s ...", meeting.recall_bot_id)
        try:
            bot_data = recall_service.get_bot(meeting.recall_bot_id)
        except requests.RequestException as exc:
            logger.error("Failed to fetch bot data from Recall AI: %s", exc)
            return 1

        recording_data = recall_service.latest_recording(bot_data)
        if not recording_data:
            logger.error(
                "Recall AI returned no recording data for bot ID %s. "
                "The recording may not be ready yet or may have expired.",
                meeting.recall_bot_id,
            )
            return 1

        recall_recording_id = recording_data.get("id")
        recording_status = (recording_data.get("status") or {}).get("code", "unknown")
        logger.info(
            "Recall recording found. Recording ID: %s. Status: %s.",
            recall_recording_id,
            recording_status,
        )

        if recording_status != "done":
            logger.warning(
                "Recording status is '%s', not 'done'. Media URLs may not be available yet. "
                "Proceeding anyway...",
                recording_status,
            )

        # ── Step 4: Upload to S3 and update the database ────────────────────
        logger.info("Uploading media to S3 and updating the database for meeting %s ...", meeting_id)
        try:
            updated_recording = crud.upsert_recording_from_recall(
                db,
                meeting_id,
                recording_data,
                mark_links_refreshed=True,
            )
        except Exception as exc:
            logger.error("Database update failed: %s", exc)
            return 1

        if not updated_recording:
            logger.error("upsert_recording_from_recall returned None. Something went wrong.")
            return 1

        # ── Step 5: Report results ───────────────────────────────────────────
        logger.info("✅ Success! Media has been saved for meeting %s.", meeting_id)
        logger.info("  Recall Recording ID : %s", updated_recording.recall_recording_id)
        logger.info("  Recording Status    : %s", updated_recording.status)
        logger.info("  Audio URL           : %s", updated_recording.audio_download_url or "NOT AVAILABLE")
        logger.info("  Video URL           : %s", updated_recording.video_download_url or "NOT AVAILABLE")
        logger.info("  Refreshed At        : %s", updated_recording.download_urls_refreshed_at)

        if not updated_recording.audio_download_url:
            logger.warning("Audio URL is still null. Recall AI may not have the audio ready yet.")
        if not updated_recording.video_download_url:
            logger.warning("Video URL is still null. Recall AI may not have the video ready yet.")

        return 0

    except Exception as exc:
        logger.exception("Unexpected error: %s", exc)
        return 1
    finally:
        db.close()


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Backfill audio/video media for a specific meeting from Recall AI to S3."
    )
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--bot-id", type=str, help="The Recall AI bot ID")
    group.add_argument("--meeting-id", type=int, help="The meeting ID in the database")
    parser.add_argument(
        "--force",
        action="store_true",
        help="Re-upload even if audio/video URLs already exist in the database.",
    )
    args = parser.parse_args()
    return backfill_media(meeting_id=args.meeting_id, bot_id=args.bot_id, force=args.force)


if __name__ == "__main__":
    raise SystemExit(main())
