from __future__ import annotations

import json
import os
import ssl
from dataclasses import dataclass
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import urljoin
from urllib.request import Request, urlopen

import numpy as np

from core.audio.wav_for_whisper import try_load_wav_for_faster_whisper
from core.logging_config import get_logger

logger = get_logger(__name__)

DEFAULT_SERVER_URL = "http://127.0.0.1:8002"
# DEFAULT_SERVER_URL = "https://vifon.boskar.net"

TRANSCRIPTION_ENDPOINT = "/v1/audio/transcriptions"

_last_transcription_id: str | None = None


@dataclass
class HttpTranscriptionResponse:
    id: str | None
    text: str
    language: str | None
    model: str | None
    duration: float | None


def _server_url() -> str:
    return os.environ.get("CLI_SERVER_URL", DEFAULT_SERVER_URL).rstrip("/")


def _timeout_seconds() -> float:
    value = os.environ.get("CLI_SERVER_TIMEOUT", "300")
    try:
        return float(value)
    except ValueError:
        return 300.0


def _load_audio(path: str | Path) -> tuple[np.ndarray, int]:
    wav_audio = try_load_wav_for_faster_whisper(
        path,
        target_sr=22050,
    )

    if wav_audio is not None:
        return wav_audio.astype(np.float32, copy=False), 22050

    from faster_whisper.audio import decode_audio

    sample_rate = 22050
    audio = decode_audio(str(path), sampling_rate=sample_rate)
    return audio.astype(np.float32, copy=False), sample_rate



def transcribe_via_cli_server(
    audio_file: str | Path,
    *,
    timeout: float | None = None,
    language: str | None = "pl",
    initial_prompt: str | None = None,
    metadata: dict | None = None,
) -> HttpTranscriptionResponse:
    global _last_transcription_id

    timeout = _timeout_seconds() if timeout is None else timeout

    audio, sample_rate = _load_audio(audio_file)

    payload = json.dumps(
        {
            "audio": audio.tolist(),
            "sample_rate": sample_rate,
            "language": language,
            "initial_prompt": initial_prompt,
            "metadata": metadata,
        }
    ).encode("utf-8")

    payload_mb = len(payload) / (1024 * 1024)

    url = urljoin(_server_url() + "/", TRANSCRIPTION_ENDPOINT.lstrip("/"))

    logger.info(
        "Sending audio to cli-server.py: url=%s payload=%.2fMB timeout=%.0fs",
        url,
        payload_mb,
        timeout,
    )

    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    request = Request(
        url,
        data=payload,
        headers={
            "Content-Type": "application/json",
            "Content-Length": str(len(payload)),
            "User-Agent": "Faster-Whisper-Transcriber/cli-server-client",
        },
        method="POST",
    )

    try:
        with urlopen(request, timeout=timeout, context=ctx) as response:
            body = response.read().decode("utf-8")

    except HTTPError as exc:
        detail = exc.read().decode("utf-8", errors="replace")
        raise RuntimeError(
            f"cli-server.py returned HTTP {exc.code}: {detail}"
        ) from exc

    except URLError as exc:
        raise RuntimeError(
            f"Cannot connect to cli-server.py at {_server_url()}: {exc.reason}"
        ) from exc

    data = json.loads(body)

    _last_transcription_id = data.get("id")

    return HttpTranscriptionResponse(
        id=_last_transcription_id,
        text=str(data.get("text", "")),
        language=data.get("language"),
        model=data.get("model"),
        duration=float(audio.shape[0]) / sample_rate if sample_rate > 0 else None,
    )


def update_transcription(
    text: str,
    *,
    timeout: float | None = None,
):
    global _last_transcription_id

    if not _last_transcription_id:
        logger.debug("No transcription id available, skipping update.")
        return

    timeout = _timeout_seconds() if timeout is None else timeout

    url = urljoin(
        _server_url() + "/",
        f"{TRANSCRIPTION_ENDPOINT.lstrip('/')}/{_last_transcription_id}",
    )

    payload = json.dumps(
        {
            "text": text,
        }
    ).encode("utf-8")

    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

    request = Request(
        url,
        data=payload,
        headers={
            "Content-Type": "application/json",
            "Content-Length": str(len(payload)),
            "User-Agent": "Faster-Whisper-Transcriber/cli-server-client",
        },
        method="PUT",
    )

    try:
        with urlopen(request, timeout=timeout, context=ctx):
            logger.debug(
                "Updated transcription %s",
                _last_transcription_id,
            )

    except HTTPError as exc:
        detail = exc.read().decode("utf-8", errors="replace")
        logger.warning(
            "Update failed: HTTP %s: %s",
            exc.code,
            detail,
        )

    except URLError as exc:
        logger.warning(
            "Cannot update transcription: %s",
            exc.reason,
        )