"""MeetingSession: orchestrates the detect → record → transcribe → stop lifecycle."""

from __future__ import annotations

import logging
import threading
import time
from pathlib import Path
from typing import TYPE_CHECKING, Callable, Optional

if TYPE_CHECKING:
    from meeting_helper.buffer import SentenceBuffer
    from meeting_helper.config import AppConfig
    from meeting_helper.meeting_detector import MeetingInfo

logger = logging.getLogger(__name__)


class MeetingSession:
    """Manages the full lifecycle of meeting recording and transcription.

    States: idle → active → stopping → idle
    Runs in its own background thread.
    """

    def __init__(
        self,
        config: AppConfig,
        sentence_buffer: SentenceBuffer,
        on_meeting_start: Callable[[MeetingInfo], None],
        on_meeting_end: Callable[[Optional[Path]], None],
    ) -> None:
        self._config = config
        self._buffer = sentence_buffer
        self._on_meeting_start = on_meeting_start
        self._on_meeting_end = on_meeting_end
        self._stop_event = threading.Event()
        self._thread: Optional[threading.Thread] = None

    def start(self) -> None:
        self._stop_event.clear()
        self._thread = threading.Thread(target=self._run, daemon=True)
        self._thread.start()

    def stop(self) -> None:
        self._stop_event.set()

    def _run(self) -> None:
        """Main loop: detect meeting → start capture/transcription → wait for end."""
        # ALL audio imports happen HERE (after daemon fork)
        from meeting_helper.meeting_detector import MeetingMonitor

        monitor = MeetingMonitor()
        logger.info("MeetingSession: watching for meetings (mic-based detection)...")

        while not self._stop_event.is_set():
            started, ended, meeting_info = monitor.check()

            if started and meeting_info:
                logger.info("Meeting detected: %s (%s)", meeting_info.app_name, meeting_info.meeting_name or "unnamed")
                self._run_active_session(meeting_info)
                monitor.set_meeting_ended()
                # Cooldown: wait for mic to fully release before re-monitoring
                logger.info("MeetingSession: cooldown before re-watching...")
                self._stop_event.wait(timeout=5.0)
                logger.info("MeetingSession: back to watching for meetings...")
            else:
                self._stop_event.wait(timeout=2.0)  # poll every 2s (matching meeting-noter)

    def _run_active_session(self, meeting_info: MeetingInfo) -> None:
        """Capture + transcribe + record until meeting app releases the mic.

        No silence detection — recording continues as long as the meeting app
        holds the microphone. Only MicProbe ends the session.
        """
        from meeting_helper.audio.capture import CombinedAudioCapture
        from meeting_helper.audio.transcriber import create_transcriber
        from meeting_helper.audio.encoder import RecordingSession
        from meeting_helper.daemon import MicProbe

        from meeting_helper.state import state as app_state
        self._on_meeting_start(meeting_info)

        capture = CombinedAudioCapture(sample_rate=16000)
        transcriber = None
        recording = None
        saved_path = None
        live_transcript_path = None

        try:
            capture.start()
            app_state.audio_active = True
            logger.info("Audio capture started (system_audio=%s)", capture.has_system_audio)

            # Start transcription
            transcriber = create_transcriber(
                audio_capture=capture,
                transcript_buffer=self._buffer,
                deepgram_api_key=self._config.deepgram_api_key,
                transcription_language=self._config.transcription_language,
            )

            # Update daemon metadata with transcriber name
            from meeting_helper.daemon import write_meta
            t_name = "Deepgram" if self._config.deepgram_api_key and transcriber else "Whisper"
            if transcriber is None:
                t_name = "none"
            write_meta(self._config, transcriber_name=t_name)

            # Always record to MP3
            recordings_dir = self._config.recordings_dir
            recordings_dir.mkdir(parents=True, exist_ok=True)
            recording = RecordingSession(
                output_dir=recordings_dir,
                sample_rate=capture.sample_rate,
                channels=capture.channels,
                meeting_name=meeting_info.meeting_name or meeting_info.app_name,
            )
            mp3_path = recording.start()
            live_transcript_path = mp3_path.with_suffix(".live.txt")
            logger.info("Recording to: %s", mp3_path.name)

            mic_probe = MicProbe(probe_interval=8.0, settle_time=0.5, required_off_count=2)

            while not self._stop_event.is_set():
                audio = capture.get_audio(timeout=0.5)
                if audio is None:
                    continue

                audio_flat = audio[:, 0] if audio.ndim > 1 else audio

                # Write to MP3
                if recording.is_active:
                    recording.write(audio)

                # Write live transcript to file periodically
                if live_transcript_path and len(self._buffer) > 0:
                    try:
                        live_transcript_path.write_text(self._buffer.get_full_transcript())
                    except Exception:
                        pass

                # MicProbe: only way to end session — meeting app released the mic
                if mic_probe.should_probe(time.time()):
                    if mic_probe.probe(capture):
                        logger.info("MicProbe: meeting app released mic — ending session")
                        break

        except Exception as exc:
            logger.error("Session error: %s", exc)
        finally:
            if transcriber is not None:
                transcriber.stop()

            capture.stop()
            app_state.audio_active = False

            # Save final live transcript
            if live_transcript_path:
                try:
                    live_transcript_path.write_text(self._buffer.get_full_transcript())
                except Exception:
                    pass

            # Finalize MP3
            if recording is not None and recording.is_active:
                saved_path, duration = recording.stop()
                if saved_path:
                    logger.info("Recording saved: %s (%.1fs)", saved_path.name, duration)

            self._buffer.clear()
            self._on_meeting_end(saved_path)
