#!/usr/bin/env python3
import argparse
import os
import shutil
import requests
import json
import re
import sys
from pathlib import Path

try:
    import instaloader
except Exception as e:
    print(f"Error: instaloader not installed. Run: pip install -r requirements.txt\n{e}", file=sys.stderr)
    sys.exit(1)


def extract_shortcode_from_url(url: str):
    m = re.search(r"instagram\.com\/(?:p|reel)\/([^\/?#]+)", url, re.I)
    return m.group(1) if m else None


def main():
    parser = argparse.ArgumentParser(description="Download Instagram post media using Instaloader")
    parser.add_argument('--url', required=True, help='Instagram post/reel URL')
    parser.add_argument('--out', default='downloads', help='Output directory (default: downloads)')
    parser.add_argument('--username', default=os.getenv('IG_USERNAME'), help='Instagram username (env IG_USERNAME)')
    parser.add_argument('--password', default=os.getenv('IG_PASSWORD'), help='Instagram password (env IG_PASSWORD)')
    parser.add_argument('--sessionfile', default=os.getenv('IG_SESSIONFILE'), help='Instaloader session file path (env IG_SESSIONFILE)')
    args = parser.parse_args()

    shortcode = extract_shortcode_from_url(args.url)
    if not shortcode:
        print('Error: Could not parse shortcode from URL', file=sys.stderr)
        sys.exit(2)

    out_dir = Path(args.out).resolve()
    out_dir.mkdir(parents=True, exist_ok=True)

    L = instaloader.Instaloader(
        download_comments=False,
        post_metadata_txt_pattern='',
        download_video_thumbnails=False,
        save_metadata=False,
        compress_json=False,
        quiet=True,
    )
    # Silence logging further to keep stdout clean for the final path only
    try:
        L.context.log = lambda *_a, **_k: None  # type: ignore[attr-defined]
        L.context.log_progress = lambda *_a, **_k: None  # type: ignore[attr-defined]
        L.context.error = lambda *_a, **_k: None  # type: ignore[attr-defined]
        L.context.warning = lambda *_a, **_k: None  # type: ignore[attr-defined]
    except Exception:
        pass

    # Login if possible
    if args.sessionfile and args.username:
        try:
            L.load_session_from_file(args.username, args.sessionfile)
        except Exception as e:
            print(f"Warning: failed to load session from {args.sessionfile}: {e}", file=sys.stderr)
    elif args.username and args.password:
        try:
            L.login(args.username, args.password)
        except Exception as e:
            print(f"Warning: login failed: {e}", file=sys.stderr)

    # Resolve and download
    try:
        post = instaloader.Post.from_shortcode(L.context, shortcode)
    except Exception as e:
        print(f"Error: resolve failed: {e}", file=sys.stderr)
        sys.exit(3)

    # Prefer downloading just the first video directly into out_dir as <shortcode>.mp4
    video_url = None
    try:
        if getattr(post, 'is_video', False) and getattr(post, 'video_url', None):
            video_url = post.video_url
        else:
            # Sidecar posts may contain one or more videos
            for node in post.get_sidecar_nodes():
                if getattr(node, 'is_video', False) and getattr(node, 'video_url', None):
                    video_url = node.video_url
                    break
    except Exception:
        video_url = None

    dest_path = (out_dir / f"{shortcode}.mp4").resolve()
    description = ''
    try:
        description = getattr(post, 'caption', '') or ''
    except Exception:
        description = ''

    if video_url:
        try:
            with requests.get(video_url, stream=True, headers={
                'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123 Safari/537.36',
                'accept': '*/*',
                'referer': 'https://www.instagram.com/',
            }, timeout=60) as r:
                r.raise_for_status()
                with open(dest_path, 'wb') as f:
                    for chunk in r.iter_content(chunk_size=1024 * 256):
                        if chunk:
                            f.write(chunk)
            print(json.dumps({"video_path": dest_path.as_posix(), "description": description}, ensure_ascii=False))
            return
        except Exception:
            # Fall back to full download if direct fetch fails
            pass

    # Fallback: Use Instaloader's downloader into a temp subdir, then move the first mp4 up
    try:
        target = out_dir / shortcode
        target.mkdir(parents=True, exist_ok=True)
        L.download_post(post, target.as_posix())
        mp4s = sorted(target.glob('*.mp4'))
        if not mp4s:
            print('No video found (post may be image-only)', file=sys.stderr)
            sys.exit(4)
        src_path = mp4s[0]
        if dest_path.exists():
            dest_path.unlink()
        shutil.move(src_path.as_posix(), dest_path.as_posix())
        print(json.dumps({"video_path": dest_path.as_posix(), "description": description}, ensure_ascii=False))
    except Exception as e:
        print(f"Error: download failed: {e}", file=sys.stderr)
        sys.exit(3)


if __name__ == '__main__':
    main()


