"""APNG generation module for creating animated mouth shapes."""
from pathlib import Path
from PIL import Image
from apng import APNG, PNG
from .config import DEFAULT_FRAME_DELAY, TRANSITION_FRAMES


def create_viseme_apng(
    viseme_images: dict[str, Path],
    output_path: Path,
    frame_delay: int = DEFAULT_FRAME_DELAY
) -> Path:
    """
    Create an APNG file from a set of viseme images.

    Args:
        viseme_images: Dict mapping viseme codes to image paths
        output_path: Path to save the APNG file
        frame_delay: Delay between frames in milliseconds

    Returns:
        Path to the created APNG file
    """
    apng = APNG()

    for viseme, image_path in viseme_images.items():
        apng.append_file(str(image_path), delay=frame_delay)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    apng.save(str(output_path))

    return output_path


def create_transition_apng(
    from_image: Path,
    to_image: Path,
    output_path: Path,
    num_frames: int = TRANSITION_FRAMES,
    frame_delay: int = DEFAULT_FRAME_DELAY // 2
) -> Path:
    """
    Create a smooth transition APNG between two viseme images.

    Args:
        from_image: Starting viseme image
        to_image: Ending viseme image
        output_path: Path to save the transition APNG
        num_frames: Number of intermediate frames
        frame_delay: Delay per frame in milliseconds

    Returns:
        Path to the created APNG file
    """
    img1 = Image.open(from_image)
    img2 = Image.open(to_image)

    # Ensure same size
    if img1.size != img2.size:
        img2 = img2.resize(img1.size)

    apng = APNG()

    # Add starting frame
    apng.append_file(str(from_image), delay=frame_delay)

    # Create intermediate frames using alpha blending
    for i in range(1, num_frames + 1):
        alpha = i / (num_frames + 1)
        blended = Image.blend(img1, img2, alpha)

        # Save temporary frame
        temp_path = output_path.parent / f"temp_frame_{i}.png"
        blended.save(temp_path)
        apng.append_file(str(temp_path), delay=frame_delay)

    # Add ending frame
    apng.append_file(str(to_image), delay=frame_delay)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    apng.save(str(output_path))

    # Clean up temp files
    for i in range(1, num_frames + 1):
        temp_path = output_path.parent / f"temp_frame_{i}.png"
        temp_path.unlink(missing_ok=True)

    return output_path


def create_lipsync_sequence_apng(
    viseme_sequence: list[str],
    viseme_images: dict[str, Path],
    output_path: Path,
    frame_delay: int = DEFAULT_FRAME_DELAY,
    add_transitions: bool = True
) -> Path:
    """
    Create an APNG animation from a sequence of visemes.

    Args:
        viseme_sequence: List of viseme codes in order
        viseme_images: Dict mapping viseme codes to image paths
        output_path: Path to save the APNG
        frame_delay: Delay between main frames
        add_transitions: Whether to add smooth transitions

    Returns:
        Path to the created APNG
    """
    apng = APNG()

    for i, viseme in enumerate(viseme_sequence):
        if viseme not in viseme_images:
            print(f"Warning: Viseme '{viseme}' not found, using 'rest'")
            viseme = "rest"

        image_path = viseme_images[viseme]
        apng.append_file(str(image_path), delay=frame_delay)

        # Add transition frames to next viseme
        if add_transitions and i < len(viseme_sequence) - 1:
            next_viseme = viseme_sequence[i + 1]
            if next_viseme not in viseme_images:
                next_viseme = "rest"

            next_image_path = viseme_images[next_viseme]

            # Create blended transition frames
            img1 = Image.open(image_path)
            img2 = Image.open(next_image_path)

            if img1.size != img2.size:
                img2 = img2.resize(img1.size)

            for j in range(1, TRANSITION_FRAMES + 1):
                alpha = j / (TRANSITION_FRAMES + 1)
                blended = Image.blend(img1, img2, alpha)

                temp_path = output_path.parent / f"temp_trans_{i}_{j}.png"
                blended.save(temp_path)
                apng.append_file(str(temp_path), delay=frame_delay // 2)

    output_path.parent.mkdir(parents=True, exist_ok=True)
    apng.save(str(output_path))

    # Clean up temp files
    for temp_file in output_path.parent.glob("temp_trans_*.png"):
        temp_file.unlink(missing_ok=True)

    return output_path
