"""Tests for /api/ai/* endpoints — chat sanity and Whisper transcribe fallback."""
import os
import io
import math
import struct
import wave
import pytest
import requests

BASE_URL = os.environ.get("REACT_APP_BACKEND_URL", "https://offline-billing-pro-2.preview.emergentagent.com").rstrip("/")


def _make_tone_wav(duration_s: float = 1.0, freq: int = 440, rate: int = 16000) -> bytes:
    """Generate a small PCM WAV in-memory (tone + silence). Whisper-compatible."""
    buf = io.BytesIO()
    with wave.open(buf, "wb") as w:
        w.setnchannels(1)
        w.setsampwidth(2)
        w.setframerate(rate)
        n = int(duration_s * rate)
        for i in range(n):
            amp = int(2000 * math.sin(2 * math.pi * freq * i / rate)) if i < n // 2 else 0
            w.writeframes(struct.pack("<h", amp))
    return buf.getvalue()


@pytest.mark.timeout(60)
class TestAiAssistant:
    def test_chat_returns_reply(self, admin_session):
        r = admin_session.post(
            f"{BASE_URL}/api/ai/chat",
            json={"message": "Aaj ka profit kitna hai?", "company_id": "", "session_id": "test-chat-1"},
            timeout=45,
        )
        assert r.status_code == 200, r.text
        data = r.json()
        assert "reply" in data and isinstance(data["reply"], str) and len(data["reply"]) > 0
        # Should NOT return 409 — that was a false alarm
        assert r.status_code != 409

    def test_chat_requires_message(self, admin_session):
        r = admin_session.post(
            f"{BASE_URL}/api/ai/chat",
            json={"message": "", "company_id": ""},
            timeout=15,
        )
        assert r.status_code == 400

    def test_transcribe_requires_auth(self):
        # No session → must be 401
        wav = _make_tone_wav()
        r = requests.post(
            f"{BASE_URL}/api/ai/transcribe",
            files={"file": ("voice.wav", wav, "audio/wav")},
            timeout=30,
        )
        assert r.status_code == 401, r.text

    def test_transcribe_rejects_empty_upload(self, admin_session):
        # Use a fresh request with the admin's cookies — requests' files= needs a Session.request
        r = admin_session.post(
            f"{BASE_URL}/api/ai/transcribe",
            files={"file": ("voice.wav", b"", "audio/wav")},
            timeout=30,
            # Override default JSON Content-Type from the fixture
            headers={"Content-Type": None} if False else None,
        )
        # When admin_session has Content-Type: application/json header, files= still works because
        # requests overrides it for multipart. But we explicitly hit empty body → 400.
        assert r.status_code in (400, 422), r.text

    def test_transcribe_happy_path(self, admin_session):
        wav = _make_tone_wav()
        # admin_session was built with Content-Type: application/json — override for multipart
        sess = requests.Session()
        sess.cookies.update(admin_session.cookies)
        r = sess.post(
            f"{BASE_URL}/api/ai/transcribe",
            files={"file": ("voice.wav", wav, "audio/wav")},
            data={"language": "en"},
            timeout=60,
        )
        assert r.status_code == 200, r.text
        data = r.json()
        assert "transcript" in data
        # Whisper should at least return some non-error response (often "BEEP" or similar for tone)
        assert isinstance(data["transcript"], str)
        assert data["bytes"] == len(wav)

    def test_transcribe_too_large(self, admin_session):
        # Send 25 MB of data — server caps at 24 MB, should 413
        # Build a multipart with raw bytes — no need to make it valid audio since size check runs first
        sess = requests.Session()
        sess.cookies.update(admin_session.cookies)
        big = b"\x00" * (25 * 1024 * 1024)
        r = sess.post(
            f"{BASE_URL}/api/ai/transcribe",
            files={"file": ("big.wav", big, "audio/wav")},
            timeout=120,
        )
        assert r.status_code == 413, f"expected 413 got {r.status_code}"
