"""AI client: real-time Claude queries, post-meeting transcription & summarization."""

from __future__ import annotations

import logging
import time
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from meeting_helper.config import AppConfig
    from meeting_helper.state import AppState

logger = logging.getLogger(__name__)


# ---------------------------------------------------------------------------
# Message assembly
# ---------------------------------------------------------------------------

def _assemble_messages(state: "AppState", config: "AppConfig") -> list:
    """Build the messages list: conversation history + current transcript window."""
    transcript = ""
    if state.sentence_buffer is not None:
        transcript = state.sentence_buffer.get_last_n_as_text(config.sentence_window)

    if transcript:
        content = f"## Recent meeting conversation (last {config.sentence_window} sentences):\n\n{transcript}"
    else:
        content = "No transcript captured yet. The meeting may have just started."

    messages = list(state.conversation_history)
    messages.append({"role": "user", "content": content})
    return messages


# ---------------------------------------------------------------------------
# Real-time query (during meeting, hotkey-triggered)
# ---------------------------------------------------------------------------

async def handle_query(state: "AppState", config: "AppConfig") -> None:
    """Assemble context from transcript buffer and stream Claude response via WebSocket."""
    from meeting_helper.server.websocket import broadcast
    import anthropic

    if state.status == "processing":
        logger.debug("Query already in progress, ignoring duplicate trigger")
        return

    state.status = "processing"
    await broadcast({"type": "status", "value": "processing"})
    await broadcast({"type": "start"})

    messages = _assemble_messages(state, config)
    current_user_turn = messages[-1]
    system_prompt = state.system_prompt or config.system_prompt

    if not config.anthropic_api_key:
        await broadcast({"type": "error", "message": "No Anthropic API key configured."})
        state.status = "listening" if state.audio_active else "idle"
        await broadcast({"type": "status", "value": state.status})
        return

    client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)
    full_text = ""

    try:
        async with client.messages.stream(
            model=config.claude_model,
            max_tokens=config.max_tokens,
            system=system_prompt,
            messages=messages,
        ) as stream:
            async for text_delta in stream.text_stream:
                full_text += text_delta
                await broadcast({"type": "chunk", "text": text_delta})

        state.last_response = full_text
        state.conversation_history.append(current_user_turn)
        state.conversation_history.append({"role": "assistant", "content": full_text})

        # Trim history to max turns
        max_entries = config.max_history_turns * 2
        if len(state.conversation_history) > max_entries:
            state.conversation_history = state.conversation_history[-max_entries:]

        await broadcast({"type": "done", "full_text": full_text})
        logger.info("Claude query complete (%d chars)", len(full_text))

    except anthropic.AuthenticationError:
        msg = "Invalid Anthropic API key. Check your configuration."
        logger.error(msg)
        await broadcast({"type": "error", "message": msg})

    except anthropic.BadRequestError as exc:
        if "token" in str(exc).lower():
            # Context too long — trim history and retry
            trimmed = len(state.conversation_history)
            half = max(2, len(state.conversation_history) // 2)
            state.conversation_history = state.conversation_history[half:]
            logger.warning("Context too long (%d entries) — trimmed to %d, retrying",
                           trimmed, len(state.conversation_history))

            await broadcast({"type": "start"})
            messages_retry = list(state.conversation_history)
            messages_retry.append(current_user_turn)
            try:
                full_text = ""
                async with client.messages.stream(
                    model=config.claude_model,
                    max_tokens=config.max_tokens,
                    system=system_prompt,
                    messages=messages_retry,
                ) as stream:
                    async for text_delta in stream.text_stream:
                        full_text += text_delta
                        await broadcast({"type": "chunk", "text": text_delta})

                state.last_response = full_text
                state.conversation_history.append(current_user_turn)
                state.conversation_history.append({"role": "assistant", "content": full_text})
                await broadcast({"type": "done", "full_text": full_text})
            except Exception as retry_exc:
                logger.error("Retry after trim failed: %s", retry_exc)
                await broadcast({"type": "error", "message": f"Failed after trimming: {retry_exc}"})
        else:
            logger.error("Bad request: %s", exc)
            await broadcast({"type": "error", "message": f"Bad request: {exc}"})

    except anthropic.APIConnectionError as exc:
        logger.error("Connection error: %s", exc)
        await broadcast({"type": "error", "message": f"Connection error: {exc}"})

    except Exception as exc:
        logger.error("Unexpected error: %s", exc)
        await broadcast({"type": "error", "message": f"Unexpected error: {exc}"})

    finally:
        state.status = "listening" if state.audio_active else "idle"
        await broadcast({"type": "status", "value": state.status})


# ---------------------------------------------------------------------------
# Manual query (user-typed text during meeting)
# ---------------------------------------------------------------------------

async def handle_manual_query(state: "AppState", config: "AppConfig", user_text: str) -> None:
    """Send a user-typed question to Claude, with transcript context appended."""
    from meeting_helper.server.websocket import broadcast
    import anthropic

    if state.status == "processing":
        logger.debug("Query already in progress, ignoring duplicate trigger")
        return

    state.status = "processing"
    await broadcast({"type": "status", "value": "processing"})
    await broadcast({"type": "start"})

    # Build the user message: their question + more transcript for context
    # Use 3x the normal window for manual queries since the user typed a specific question
    transcript = ""
    if state.sentence_buffer is not None:
        transcript = state.sentence_buffer.get_last_n_as_text(config.sentence_window * 3)

    if transcript:
        content = f"{user_text}\n\n---\n## Recent meeting transcript (for context):\n{transcript}"
    else:
        content = user_text

    messages = list(state.conversation_history)
    messages.append({"role": "user", "content": content})
    current_user_turn = {"role": "user", "content": content}
    system_prompt = state.system_prompt or config.system_prompt

    if not config.anthropic_api_key:
        await broadcast({"type": "error", "message": "No Anthropic API key configured."})
        state.status = "listening" if state.audio_active else "idle"
        await broadcast({"type": "status", "value": state.status})
        return

    client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)
    full_text = ""

    try:
        async with client.messages.stream(
            model=config.claude_model,
            max_tokens=config.max_tokens,
            system=system_prompt,
            messages=messages,
        ) as stream:
            async for text_delta in stream.text_stream:
                full_text += text_delta
                await broadcast({"type": "chunk", "text": text_delta})

        state.last_response = full_text
        state.conversation_history.append(current_user_turn)
        state.conversation_history.append({"role": "assistant", "content": full_text})

        max_entries = config.max_history_turns * 2
        if len(state.conversation_history) > max_entries:
            state.conversation_history = state.conversation_history[-max_entries:]

        await broadcast({"type": "done", "full_text": full_text})
        logger.info("Manual query complete (%d chars)", len(full_text))

    except Exception as exc:
        logger.error("Manual query error: %s", exc)
        await broadcast({"type": "error", "message": f"Error: {exc}"})

    finally:
        state.status = "listening" if state.audio_active else "idle"
        await broadcast({"type": "status", "value": state.status})


# ---------------------------------------------------------------------------
# Post-meeting: transcribe MP3 with faster-whisper
# ---------------------------------------------------------------------------

def transcribe_audio_file(mp3_path: str, config: "AppConfig") -> str:
    """Transcribe an MP3 file using faster-whisper. Returns full transcript text.

    Runs synchronously — caller should wrap in asyncio.to_thread().
    """
    from faster_whisper import WhisperModel

    path = Path(mp3_path)
    if not path.exists():
        raise FileNotFoundError(f"Audio file not found: {mp3_path}")

    logger.info("Transcribing %s with faster-whisper...", path.name)
    t0 = time.monotonic()

    model = WhisperModel("small", compute_type="int8")
    segments, info = model.transcribe(
        str(path),
        language=config.transcription_language if config.transcription_language != "auto" else None,
        beam_size=5,
        vad_filter=True,
    )

    lines: list[str] = []
    for segment in segments:
        start_m, start_s = divmod(int(segment.start), 60)
        end_m, end_s = divmod(int(segment.end), 60)
        timestamp = f"[{start_m:02d}:{start_s:02d} - {end_m:02d}:{end_s:02d}]"
        lines.append(f"{timestamp} {segment.text.strip()}")

    transcript = "\n".join(lines)
    elapsed = time.monotonic() - t0
    logger.info("Transcription complete: %d segments, %.1fs", len(lines), elapsed)

    # Save alongside the MP3
    out_path = path.with_suffix(".transcript.txt")
    out_path.write_text(transcript)
    logger.info("Transcript saved: %s", out_path.name)

    return transcript


# ---------------------------------------------------------------------------
# Post-meeting: summarize transcript with Claude
# ---------------------------------------------------------------------------

async def summarize_transcript(transcript_path: str, config: "AppConfig") -> str:
    """Send a full transcript to Claude for structured summary. Returns summary text."""
    import anthropic
    from meeting_helper.ai.prompts import SUMMARIZE_SYSTEM_PROMPT

    path = Path(transcript_path)
    if not path.exists():
        raise FileNotFoundError(f"Transcript file not found: {transcript_path}")

    transcript = path.read_text()
    if not transcript.strip():
        raise ValueError("Transcript file is empty")

    if not config.anthropic_api_key:
        raise ValueError("No Anthropic API key configured")

    logger.info("Summarizing transcript (%d chars)...", len(transcript))
    t0 = time.monotonic()

    client = anthropic.AsyncAnthropic(api_key=config.anthropic_api_key)

    message = await client.messages.create(
        model=config.claude_model,
        max_tokens=config.max_tokens,
        system=SUMMARIZE_SYSTEM_PROMPT,
        messages=[{"role": "user", "content": f"Please summarize this meeting transcript:\n\n{transcript}"}],
    )

    summary = message.content[0].text
    elapsed = time.monotonic() - t0
    logger.info("Summarization complete: %d chars, %.1fs", len(summary), elapsed)

    # Save alongside the transcript
    out_path = path.with_name(path.name.replace(".transcript.txt", ".summary.txt"))
    if out_path == path:
        out_path = path.with_suffix(".summary.txt")
    out_path.write_text(summary)
    logger.info("Summary saved: %s", out_path.name)

    return summary
