import logging

from dotenv import load_dotenv
from livekit.agents import (NOT_GIVEN,Agent,AgentFalseInterruptionEvent,AgentSession,JobContext,JobProcess,MetricsCollectedEvent,RoomInputOptions,RoomOutputOptions,RunContext,WorkerOptions,cli,metrics)
from livekit import rtc, api
from livekit.agents.llm import function_tool
from livekit.plugins import (google, noise_cancellation, silero)
from livekit.plugins.turn_detector.multilingual import MultilingualModel

logger = logging.getLogger("agent")
logger.setLevel(logging.INFO)

load_dotenv()

class Assistant(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions="""You are a helpful and friendly assistant. You always answer questions based on your knowledge. 
            You must reply only in Marathi language. At the end of every response, politely ask: 'आपल्याला अजून काही मदत हवी आहे का?'""",
        )

    async def on_enter(self):
        self.session.generate_reply(instructions="Greet the user properly by saying hello how can i help you and offer your assistance.You must only use Marathi language.")    


def prewarm(proc: JobProcess):
    proc.userdata["vad"] = silero.VAD.load()


async def entrypoint(ctx: JobContext):
    # Logging setup
    # Add any other context you want in all log entries here
    ctx.log_context_fields = {"room": ctx.room.name}

    # Set up a voice AI pipeline using OpenAI, Cartesia, Deepgram, and the LiveKit turn detector
    session = AgentSession(
        vad=ctx.proc.userdata["vad"],
        llm=google.LLM(model="gemini-2.0-flash-exp"),
        stt=google.STT(model="latest_long", spoken_punctuation=False, languages="mr-IN", detect_language=True, interim_results=True, punctuate=False, use_streaming=True ), 
        tts=google.TTS(gender="female", voice_name="mr-IN-Chirp3-HD-Achernar",language="mr-IN", use_streaming=True),
        turn_detection=MultilingualModel(),
        preemptive_generation=True, # Whether to speculatively begin LLM and TTS requests before an end-of-turn is detected. When True, the agent sends inference calls as soon as a user transcript is received rather than waiting for a definitive turn boundary. This can reduce response latency by overlapping model inference with user audio, but may incur extra compute if the user interrupts or revises mid-utterance.
    )


    # sometimes background noise could interrupt the agent session, these are considered false positive interruptions
    # when it's detected, you may resume the agent's speech
    @session.on("agent_false_interruption")
    def _on_agent_false_interruption(ev: AgentFalseInterruptionEvent):
        logger.info("false positive interruption, resuming")
        session.generate_reply(instructions=ev.extra_instructions or NOT_GIVEN)

    # Metrics collection, to measure pipeline performance
    # For more information, see https://docs.livekit.io/agents/build/metrics/
    usage_collector = metrics.UsageCollector()

    @session.on("metrics_collected")
    def _on_metrics_collected(ev: MetricsCollectedEvent):
        metrics.log_metrics(ev.metrics)
        usage_collector.collect(ev.metrics)

    async def log_usage():
        summary = usage_collector.get_summary()
        logger.info(f"Usage: {summary}")

    ctx.add_shutdown_callback(log_usage)

    # # Add a virtual avatar to the session, if desired
    # # For other providers, see https://docs.livekit.io/agents/integrations/avatar/
    # avatar = hedra.AvatarSession(
    #   avatar_id="...",  # See https://docs.livekit.io/agents/integrations/avatar/hedra
    # )
    # # Start the avatar and wait for it to join
    # await avatar.start(session, room=ctx.room)

    # Start the session, which initializes the voice pipeline and warms up the models
    await session.start(
        agent=Assistant(),
        room=ctx.room,
        room_input_options=RoomInputOptions(noise_cancellation=noise_cancellation.BVC()),
        room_output_options=RoomOutputOptions(transcription_enabled=True, sync_transcription=True)   # -> Check other Parameters
    )

    # Join the room and connect to the user
    await ctx.connect()


if __name__ == "__main__":
    cli.run_app(WorkerOptions(agent_name="simple-agent-1",entrypoint_fnc=entrypoint, prewarm_fnc=prewarm))
