import argparse
import json
import os
import uuid
from pathlib import Path
from typing import Dict, List, Optional, Tuple
import cv2
from pdf2image import convert_from_path
from PIL import Image, ImageDraw
import numpy as np
from moviepy.editor import ImageClip, AudioFileClip, VideoFileClip, CompositeVideoClip, concatenate_videoclips
from moviepy.video.VideoClip import ColorClip
from dotenv import load_dotenv

load_dotenv()  # take environment variables from .env if available
poppler_path= os.getenv("POPPLER_PATH")
print("Poppler path", poppler_path)

def pdf_to_images(pdf_path: str, out_dir: str, dpi: int = 150, poppler_path: Optional[str] = None) -> List[Path]:
    """
    Convert PDF pages to images using pdf2image.
    Returns list of image Paths in page order (1-based indexing -> list index 0 = page 1).
    poppler_path: optionally required on Windows to point to poppler bin folder.
    """
    p = Path(pdf_path)
    if not p.exists():
        raise FileNotFoundError(f"PDF not found: {pdf_path}")
    outdir = Path(out_dir)
    outdir.mkdir(parents=True, exist_ok=True)

    # convert_from_path returns PIL images in order
    images = convert_from_path(str(p), dpi=dpi, poppler_path=poppler_path)
    saved: List[Path] = []
    for i, img in enumerate(images, start=1):
        out_file = outdir / f"page_{i:03d}.png"
        img.save(out_file, format="PNG")
        saved.append(out_file)
    return saved

def load_audio_map(path_or_dict) -> Dict[int, str]:
    """
    Load audio map from JSON filepath or accept a dict. Keys expected to be page numbers (1-based).
    Returns dict[int,page_audio_path].
    """
    if isinstance(path_or_dict, dict):
        d = path_or_dict
    else:
        p = Path(path_or_dict)
        if not p.exists():
            raise FileNotFoundError(f"Audio map not found: {path_or_dict}")
        d = json.loads(p.read_text(encoding="utf-8"))
    out: Dict[int,str] = {}
    for k, v in d.items():
        try:
            n = int(k)
        except:
            raise ValueError(f"Audio map key is not integer-like: {k}")
        out[n] = str(v)
    return out

def create_circle_mask_array(size: Tuple[int,int], border: int = 0) -> np.ndarray:
    """Return grayscale mask (0..255) with a filled circle."""
    w,h = size
    mask = Image.new("L", (w, h), 0)
    draw = ImageDraw.Draw(mask)
    draw.ellipse((border, border, w-1-border, h-1-border), fill=255)
    return np.array(mask)

def make_avatar_clip_for_duration(avatar_path: str, duration: float, avatar_size: Tuple[int,int]):
    """Load avatar video, loop to duration, resize, and return clip (without audio)."""
    avatar = VideoFileClip(avatar_path).without_audio()
    avatar_looped = avatar.loop(duration=duration)
    avatar_resized = avatar_looped.resize(newsize=avatar_size)
    return avatar_resized

def extract_icon(video_path, output_dir="uploads/thumbnails", frame_number=0):
    """
    Extracts a frame from a video file and saves it as an image (icon).

    Args:
        video_path (str): Path to the input video file (.mp4).
        output_dir (str): Directory where the image will be saved.
        frame_number (int): Frame number to extract (default: first frame).

    Returns:
        str: Path to the saved image.
    """
    # Ensure valid path
    if not isinstance(video_path, str) or not os.path.exists(video_path):
        raise ValueError(f"Invalid video path: {video_path}")

    # Create output directory if needed
    os.makedirs(output_dir, exist_ok=True)

    # Read the video
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        raise ValueError(f"Unable to open video: {video_path}")

    # Jump to specified frame
    cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)

    # Read the frame
    success, frame = cap.read()
    cap.release()

    if not success or frame is None:
        raise ValueError("Failed to read frame from video.")

    # Create output image path
    base_name = os.path.splitext(os.path.basename(video_path))[0]
    output_path = os.path.join(output_dir, f"{base_name}_icon.jpg")

    # Save the frame as an image
    cv2.imwrite(output_path, frame)

    return output_path