"""LemonSlice/Daily avatar transport for an existing Pipecat voice pipeline.

The caller supplies configured STT, LLM, TTS, and context aggregators.
Constructing the pipeline makes no provider session or room requests. Running
the worker is the explicit live boundary and can incur provider charges.
"""

from __future__ import annotations

import os
from dataclasses import dataclass, field
from urllib.parse import urlparse

import aiohttp
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.worker import PipelineParams, PipelineWorker
from pipecat.transports.lemonslice.transport import (
    LemonSliceNewSessionRequest,
    LemonSliceParams,
    LemonSliceTransport,
)
from pipecat.workers.runner import WorkerRunner


@dataclass(frozen=True)
class AvatarConfig:
    image_url: str
    daily_room_url: str
    api_key: str = field(repr=False)
    daily_token: str = field(repr=False)
    idle_timeout: int = 60

    def __post_init__(self) -> None:
        for name, value in (("image", self.image_url), ("Daily room", self.daily_room_url)):
            parsed = urlparse(value)
            if parsed.scheme != "https" or not parsed.netloc:
                raise ValueError(f"{name} must use a public HTTPS URL")
        if not self.api_key or not self.daily_token:
            raise ValueError("Server-side LemonSlice key and Daily room token are required")
        if self.idle_timeout <= 0:
            raise ValueError("Keep a positive avatar idle timeout")

    @classmethod
    def from_environment(cls) -> "AvatarConfig":
        return cls(
            image_url=os.environ["AVATAR_IMAGE_URL"],
            daily_room_url=os.environ["DAILY_ROOM_URL"],
            api_key=os.environ["LEMONSLICE_API_KEY"],
            daily_token=os.environ["DAILY_ROOM_TOKEN"],
        )


def build_avatar_pipeline(
    http_session: aiohttp.ClientSession,
    config: AvatarConfig,
    *,
    stt,
    user_aggregator,
    llm,
    tts,
    assistant_aggregator,
    transport_factory=None,
):
    """Assemble the caller's pipeline around the official avatar transport."""
    factory = transport_factory or LemonSliceTransport
    transport = factory(
        bot_name="Best Live Avatar example",
        api_key=config.api_key,
        session=http_session,
        session_request=LemonSliceNewSessionRequest(
            agent_image_url=config.image_url,
            daily_room_url=config.daily_room_url,
            daily_token=config.daily_token,
            idle_timeout=config.idle_timeout,
        ),
        params=LemonSliceParams(
            audio_in_enabled=True,
            audio_out_enabled=True,
            microphone_out_enabled=False,
        ),
    )
    pipeline = Pipeline([
        transport.input(),
        stt,
        user_aggregator,
        llm,
        tts,
        transport.output(),
        assistant_aggregator,
    ])
    worker = PipelineWorker(
        pipeline,
        params=PipelineParams(audio_in_sample_rate=16000, audio_out_sample_rate=16000),
    )

    @transport.event_handler("on_client_disconnected")
    async def on_client_disconnected(_transport, _participant):
        await worker.cancel()

    @transport.event_handler("on_avatar_disconnected")
    async def on_avatar_disconnected(_transport, _participant, _reason):
        await worker.cancel()

    return transport, worker


async def run_avatar_pipeline(config: AvatarConfig, **voice_processors) -> None:
    """Explicit live entry point. The caller starts this after authenticating a user."""
    async with aiohttp.ClientSession() as http_session:
        _transport, worker = build_avatar_pipeline(http_session, config, **voice_processors)
        runner = WorkerRunner()
        await runner.add_workers(worker)
        await runner.run()
