"""
Module: src.app.main
Workorder: WO02
Purpose: Orchestration for ingestion, transcription, optional diarization and post-processing.

Dependencies:
    - datetime: Session metadata timestamp
    - pathlib: File path handling
    - typing: Structured return value typing
    - ingestion/transcription/export modules: Pipeline steps

Inputs:
    - Audio path and language mode

Outputs:
    - Export artifacts and payload metadata

Key Functions/Classes:
    - run_transcription_session: Executes full WO01 MVP pipeline

Tests: tests/unit/test_placeholder.py
"""
from datetime import date, datetime
from pathlib import Path
from typing import Any, Callable, Optional

from src.export.json_exporter import export_json
from src.export.json_exporter import add_ollama_output_to_export
from src.export.markdown_exporter import export_markdown
from src.export.text_exporter import export_text
from src.ingestion.normalizer import normalize_audio
from src.ingestion.validator import validate_audio_file
from src.analysis.ollama_client import (
    check_ollama_availability,
    format_ollama_protocol_text,
    get_ollama_runtime_status,
    summarize_with_ollama,
)
from src.transcription.diarization import apply_diarization
from src.transcription.prompt_builder import build_initial_prompt
from src.transcription.whisperx_pipeline import transcribe_with_whisperx


def _collect_vocabulary_terms(terms_path: Path) -> list[str]:
    if not terms_path.exists():
        return []

    import json

    with terms_path.open("r", encoding="utf-8") as file:
        raw_terms = json.load(file)

    if not isinstance(raw_terms, list):
        return []

    return [term for term in raw_terms if isinstance(term, str) and term.strip()]


def _segments_to_transcript(segments: list[dict[str, Any]]) -> str:
    lines: list[str] = []
    for segment in segments:
        speaker = str(segment.get("speaker", "Speaker 0"))
        text = str(segment.get("text", "")).strip()
        if text:
            lines.append(f"{speaker}: {text}")
    return "\n".join(lines)


def _build_session_output_dir(base_output_dir: Path, file_stem: str) -> Path:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    sanitized_stem = "".join(
        character if character.isalnum() or character in {"-", "_"} else "_"
        for character in file_stem
    ).strip("_")
    if not sanitized_stem:
        sanitized_stem = "transkription"
    return base_output_dir / f"{timestamp}_{sanitized_stem}"


def run_transcription_session(
    source_audio_path: Path,
    language_mode: str = "auto",
    terms_path: Path = Path("resources/terms.json"),
    output_dir: Path = Path("data/output"),
    diarization_enabled: bool = False,
    diarization_segments: list[dict[str, Any]] | None = None,
    progress_callback: Optional[Callable[[float], None]] = None,
) -> dict[str, Any]:
    """Execute WO01 end-to-end local transcription workflow.

    Args:
        source_audio_path: Input audio file path.
        language_mode: Language mode (`auto`, `de`, `en`).
        terms_path: Path to vocabulary terms file.
        output_dir: Export directory.
        diarization_enabled: Enables speaker mapping stage.
        diarization_segments: Optional diarization result intervals.
        progress_callback: Optional callback for UI progress updates.

    Returns:
        Dictionary containing payload and export file paths.

    Raises:
        ProcessingError: Propagated from pipeline modules.
    """
    if progress_callback is not None:
        progress_callback(0.05)

    validate_audio_file(source_audio_path)
    if progress_callback is not None:
        progress_callback(0.15)

    normalized_path = normalize_audio(source_audio_path)
    if progress_callback is not None:
        progress_callback(0.3)

    initial_prompt = build_initial_prompt(terms_path)
    vocabulary_boosted = _collect_vocabulary_terms(terms_path)

    transcription_result = transcribe_with_whisperx(
        normalized_audio_path=normalized_path,
        language_mode=language_mode,
        initial_prompt=initial_prompt,
        temperature=0.0,
        progress_callback=(
            lambda transcription_progress: progress_callback(0.3 + transcription_progress * 0.5)
            if progress_callback is not None
            else None
        ),
    )

    segments = transcription_result.get("segments", [])
    if diarization_enabled:
        segments = apply_diarization(segments, diarization_segments=diarization_segments)

    transcript_text = _segments_to_transcript(segments)

    payload = {
        "session_metadata": {
            "date": str(date.today()),
            "source": source_audio_path.name,
            "language": str(transcription_result.get("language", language_mode)),
        },
        "vocabulary_boosted": vocabulary_boosted,
        "segments": segments,
    }

    output_dir.mkdir(parents=True, exist_ok=True)
    file_stem = source_audio_path.stem
    session_output_dir = _build_session_output_dir(output_dir, file_stem)
    session_output_dir.mkdir(parents=True, exist_ok=True)

    json_path = session_output_dir / f"{file_stem}.json"
    markdown_path = session_output_dir / f"{file_stem}.md"
    text_path = session_output_dir / f"{file_stem}.txt"

    export_json(payload, json_path)
    export_markdown(transcript_text, markdown_path)
    export_text(transcript_text, text_path)

    if progress_callback is not None:
        progress_callback(1.0)

    return {
        "payload": payload,
        "transcript_text": transcript_text,
        "diarization_enabled": diarization_enabled,
        "output_dir": str(session_output_dir),
        "exports": {
            "json": str(json_path),
            "markdown": str(markdown_path),
            "text": str(text_path),
        },
    }


def run_ollama_postprocessing(
    transcript_text: str,
    model: str = "llama3.1",
    host: str = "http://localhost:11434",
    export_json_path: Path | None = None,
    export_markdown_path: Path | None = None,
    export_text_path: Path | None = None,
) -> str:
    """Run local Ollama post-processing for a transcript.

    Args:
        transcript_text: Transcript text to summarize.
        model: Ollama model name.
        host: Ollama service URL.
        export_json_path: Optional JSON export path to persist Ollama output.
        export_markdown_path: Optional markdown export path to prepend summary/frontmatter.
        export_text_path: Optional text export path to prepend summary/frontmatter.

    Returns:
        Generated post-processing output.
    """
    structured = summarize_with_ollama(
        transcript_text=transcript_text,
        model=model,
        host=host,
    )
    result = format_ollama_protocol_text(structured)

    frontmatter = {
        "date": str(date.today()),
        "title": structured.get("title") or "Transkript",
        "topic": structured.get("topic") or "",
        "speakers": structured.get("speakers") or [],
        "outcomes": structured.get("outcomes") or [],
        "action_items": structured.get("action_items") or [],
    }

    summary_text = str(structured.get("summary", "")).strip()

    if export_markdown_path is not None:
        export_markdown(
            transcript=transcript_text,
            target_path=export_markdown_path,
            summary_text=summary_text,
            frontmatter=frontmatter,
        )

    if export_text_path is not None:
        export_text(
            transcript=transcript_text,
            target_path=export_text_path,
            summary_text=summary_text,
            frontmatter=frontmatter,
        )

    if export_json_path is not None:
        add_ollama_output_to_export(
            export_path=export_json_path,
            model=model,
            host=host,
            text=result,
            summary=summary_text,
            action_items=structured.get("action_items"),
            title=structured.get("title"),
            topic=structured.get("topic"),
            speakers=structured.get("speakers"),
            outcomes=structured.get("outcomes"),
        )
    return result


def get_ollama_service_status(host: str = "http://localhost:11434") -> bool:
    """Return local Ollama availability for UI status rendering.

    Args:
        host: Ollama host URL.

    Returns:
        True when Ollama is reachable.
    """
    return check_ollama_availability(host=host)


def get_ollama_service_runtime_status(
    model: str = "auto",
    host: str = "http://localhost:11434",
) -> dict[str, Any]:
    """Return detailed runtime status for local Ollama.

    Args:
        model: Requested model name or `auto`.
        host: Ollama host URL.

    Returns:
        Status dictionary for UI diagnostics.
    """
    return get_ollama_runtime_status(requested_model=model, host=host)


def run_app() -> None:
    """Compatibility entrypoint for running Streamlit UI wrapper."""
    from src.ui.streamlit_app import render_ui

    render_ui()

