import asyncio
import random
import signal
import sys

from dotenv import load_dotenv
from loguru import logger

from pipecat.frames.frames import LLMSetToolsFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.runner import PipelineRunner
from pipecat.pipeline.task import PipelineParams, PipelineTask
from pipecat.services.llm_service import FunctionCallParams
from pipecat.transports.local.audio import LocalAudioTransport, LocalAudioTransportParams

# Import our custom Deepslate Pipecat plugin
from deepslate.pipecat import DeepslateOptions, DeepslateRealtimeLLMService, ElevenLabsTtsConfig, ElevenLabsLocation

load_dotenv(override=True)

logger.remove()
logger.add(sys.stderr, level="DEBUG")


# ---------------------------------------------------------------------------
# Tool definitions (OpenAI function-calling JSON schema format)
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "lookup_weather",
            "description": "Get the current weather for a given location.",
            "parameters": {
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city or location to look up weather for.",
                    }
                },
                "required": ["location"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "get_current_location",
            "description": "Get the user's current location.",
            "parameters": {
                "type": "object",
                "properties": {},
            },
        },
    },
]


# ---------------------------------------------------------------------------
# Function handlers
# ---------------------------------------------------------------------------

async def lookup_weather(params: FunctionCallParams):
    location = params.arguments.get("location", "unknown")
    result = {
        "location": location,
        "temperature_celsius": random.randint(10, 35),
        "precipitation": random.choice(["none", "light", "moderate", "heavy"]),
        "air_pressure_hpa": random.randint(900, 1100),
    }
    logger.info(f"lookup_weather({location}) → {result}")
    await params.result_callback(result)


async def get_current_location(params: FunctionCallParams):
    result = {"location": "Berlin"}
    logger.info(f"get_current_location() → {result}")
    await params.result_callback(result)


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

async def main():
    # 1. Initialize Local Audio Transport (microphone in, speakers out)
    transport = LocalAudioTransport(
        params=LocalAudioTransportParams(
            audio_in_enabled=True,
            audio_out_enabled=True,
            audio_in_sample_rate=16000,
            audio_out_sample_rate=16000,
            audio_in_channels=1,
            audio_out_channels=1,
        )
    )

    # 2. Initialize Deepslate LLM Service
    try:
        opts = DeepslateOptions.from_env(
            system_prompt="Du bist ein freundlicher und hilfsbereiter KI-Assistent, der in Echtzeit auf gesprochene Anfragen reagiert. Du kannst Fragen beantworten, Informationen bereitstellen und einfache Gespräche führen."
        )
    except ValueError as e:
        logger.error(e)
        return

    tts = ElevenLabsTtsConfig.from_env()
    llm = DeepslateRealtimeLLMService(options=opts, tts_config=tts)

    logger.info("TTS location: " + tts.location.name)

    # Register function handlers
    llm.register_function("lookup_weather", lookup_weather)
    llm.register_function("get_current_location", get_current_location)

    # 3. Build the Pipeline
    pipeline = Pipeline([
        transport.input(),
        llm,
        transport.output(),
    ])

    task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))

    # Sync tool definitions with Deepslate (queued after StartFrame)
    await task.queue_frame(LLMSetToolsFrame(tools=TOOLS))

    # Allow Ctrl+C to cleanly stop the pipeline
    loop = asyncio.get_event_loop()
    loop.add_signal_handler(signal.SIGINT, lambda: asyncio.create_task(task.cancel()))

    # 4. Run the Pipeline
    runner = PipelineRunner()
    logger.info("Local audio bot started. Speak into your microphone. Press Ctrl+C to stop.")
    await runner.run(task)


if __name__ == "__main__":
    asyncio.run(main())