import logging
import pytest

from gpt_token_tracker.pricing import TOKENS_PER_PRICE


# -----------------------------
# Tests
# -----------------------------

def test_compute_costs_realtime(token_logger_realtime, fake_realtime_usage, realtime_pricing):
    costs = token_logger_realtime.compute_costs(fake_realtime_usage)

    expected_text = (50 * realtime_pricing.pricing["text_in"]) / TOKENS_PER_PRICE
    expected_audio = (100 * realtime_pricing.pricing["audio_in"]) / TOKENS_PER_PRICE
    expected_image = (10 * realtime_pricing.pricing["image_in"]) / TOKENS_PER_PRICE
    expected_cached_text = (5 * realtime_pricing.pricing["cached_text_in"]) / TOKENS_PER_PRICE
    expected_cached_audio = 0
    expected_cached_image = 0
    expected_output_text = (30 * realtime_pricing.pricing["text_out"]) / TOKENS_PER_PRICE
    expected_output_audio = (20 * realtime_pricing.pricing["audio_out"]) / TOKENS_PER_PRICE

    expected_input_total = (
        expected_text
        + expected_audio
        + expected_image
        + expected_cached_text
        + expected_cached_audio
        + expected_cached_image
    )
    expected_output_total = expected_output_text + expected_output_audio
    expected_total = expected_input_total + expected_output_total

    assert costs.input_text_cost == pytest.approx(expected_text)
    assert costs.input_audio_cost == pytest.approx(expected_audio)
    assert costs.input_image_cost == pytest.approx(expected_image)

    assert costs.cached_text_cost == pytest.approx(expected_cached_text)
    assert costs.cached_audio_cost == expected_cached_audio
    assert costs.cached_image_cost == expected_cached_image

    assert costs.text_output_cost == pytest.approx(expected_output_text)
    assert costs.audio_output_cost == pytest.approx(expected_output_audio)

    assert costs.total_input_cost == pytest.approx(expected_input_total)
    assert costs.total_output_cost == pytest.approx(expected_output_total)
    assert costs.total_cost == pytest.approx(expected_total)


def test_record_logs_realtime(log_writer, realtime_model, realtime_result, token_logger_realtime, fake_realtime_usage, caplog):
    with caplog.at_level(logging.INFO):
        token_logger_realtime.record(realtime_model, realtime_result, fake_realtime_usage)

    assert len(caplog.records) == 1
    msg = caplog.records[0].message

    assert msg == "Model: gpt-realtime-mini | Result: The capital of Ireland is Dublin | Total Tokens: 215 | Input Tokens: 165 | Output Tokens: 50 | Input Tokens: 165 | Input Text Tokens: 50 | Input Audio Tokens: 100 | Input Image Tokens: 10 | Cached Text Tokens: 5 | Cached Audio Tokens: 0 | Cached Image Tokens: 0 | Output Tokens: 50 | Output Text Tokens: 30 | Output Audio Tokens: 20 | Input Text Cost: 0.000030 | Input Audio Cost: 0.001000 | Input Image Cost: 0.000050 | Cached Text Cost: 0.000000 | Cached Audio Cost: 0.000000 | Cached Image Cost: 0.000000 | Text Output Cost: 0.000072 | Audio Output Cost: 0.000400 | Total Input Cost: 0.001080 | Total Output Cost: 0.000472 | Total Cost: 0.001552"


def test_compute_costs_realtime_transcribe(token_logger_realtime_transcribe, fake_audio_transcription_usage, realtime_transcribe_pricing):
    costs = token_logger_realtime_transcribe.compute_costs(fake_audio_transcription_usage)

    expected_text_cost = (1 * realtime_transcribe_pricing.pricing["text_in"]) / TOKENS_PER_PRICE
    expected_audio_cost = (101 * realtime_transcribe_pricing.pricing["audio_in"]) / TOKENS_PER_PRICE
    expected_output_text = (7 * realtime_transcribe_pricing.pricing["text_out"]) / TOKENS_PER_PRICE

    expected_input_total = (
        expected_text_cost
        + expected_audio_cost
    )
    expected_total = expected_input_total + expected_output_text

    assert costs.input_text_cost == pytest.approx(expected_text_cost)
    assert costs.input_audio_cost == pytest.approx(expected_audio_cost)

    assert costs.output_text_cost == pytest.approx(expected_output_text)

    assert costs.total_cost == pytest.approx(expected_total)


def test_record_logs_realtime_transcribe(log_writer, transcribe_model, realtime_transcription_result, token_logger_realtime_transcribe, fake_audio_transcription_usage, caplog):
    with caplog.at_level(logging.INFO):
        token_logger_realtime_transcribe.record(transcribe_model, realtime_transcription_result, fake_audio_transcription_usage)

    assert len(caplog.records) == 1
    msg = caplog.records[0].message

    assert msg == "Model: gpt-4o-mini-transcribe | Result: What is the capital of Ireland? | Total Tokens: 109 | Input Tokens: 102 | Output Tokens: 7 | Input Text Tokens: 1 | Input Audio Tokens: 101 | Output Text Tokens: 7 | Input Text Cost: 0.000001 | Input Audio Cost: 0.001010 | Output Text Cost: 0.000017 | Total Cost: 0.001027"


def test_compute_costs_text_completion(
    token_logger_text_completion,
    fake_text_completion_usage,
    text_completion_pricing,
):
    costs = token_logger_text_completion.compute_costs(fake_text_completion_usage)

    expected_text = (165 * text_completion_pricing.pricing["text_in"]) / TOKENS_PER_PRICE
    expected_cached_text = (5 * text_completion_pricing.pricing["cached_text_in"]) / TOKENS_PER_PRICE
    expected_output_text = (50 * text_completion_pricing.pricing["text_out"]) / TOKENS_PER_PRICE

    expected_total = expected_text + expected_cached_text + expected_output_text

    assert costs.input_text_cost == pytest.approx(expected_text)
    assert costs.cached_text_cost == pytest.approx(expected_cached_text)
    assert costs.output_text_cost == pytest.approx(expected_output_text)
    assert costs.total_cost == pytest.approx(expected_total)

    assert costs.input_text_tokens == 165
    assert costs.cached_text_tokens == 5
    assert costs.output_text_tokens == 50


def test_record_logs_text_completion(log_writer, text_completion_model, text_completion_result, token_logger_text_completion, fake_text_completion_usage, caplog):
    with caplog.at_level(logging.INFO):
        token_logger_text_completion.record(text_completion_model, text_completion_result, fake_text_completion_usage)

    assert len(caplog.records) == 1
    msg = caplog.records[0].message

    assert msg == "Model: gpt-5-mini | Result: The capital of Ireland is Dublin | Total Tokens: 215 | Input Tokens: 165 | Output Tokens: 50 | Input Text Tokens: 165 | Cached Text Tokens: 5 | Output Text Tokens: 50 | Input Text Cost: 0.000041 | Cached Text Cost: 0.000000 | Output Text Cost: 0.000100 | Total Cost: 0.000141"


def test_close_is_noop(log_writer):
    # Should not raise
    log_writer.close()
