import pytest
from datetime import datetime, timezone

from config import (
    Speaker,
    load_settings,
    validate_event_json,
    ConferenceEvent,
    WebinarEvent,
    IdleEvent,
)

VALID_CONFERENCE_NEW = b"""
{
  "event_id": "conf-2",
  "type": "conference",
  "title": "Conf 2",
  "speakers": [{"name": "S", "channel": "@s"}]
}
"""

VALID_CONFERENCE_LEGACY = b"""
{
  "conference_id": "conf-legacy",
  "title": "Legacy",
  "speakers": [{"name": "S", "channel": "@s"}]
}
"""

VALID_WEBINAR = b"""
{
  "event_id": "webinar-1",
  "type": "webinar",
  "title": "Webinar",
  "description": "Some text",
  "datetime": "2026-06-15T19:00:00+03:00",
  "duration_minutes": 60
}
"""


def test_validate_event_conference_new_schema():
    event = validate_event_json(VALID_CONFERENCE_NEW)
    assert isinstance(event, ConferenceEvent)
    assert event.event_id == "conf-2"
    assert event.type == "conference"
    assert event.title == "Conf 2"
    assert event.speakers[0].channel == "@s"


def test_validate_event_conference_legacy_maps_to_event_id():
    event = validate_event_json(VALID_CONFERENCE_LEGACY)
    assert isinstance(event, ConferenceEvent)
    assert event.event_id == "conf-legacy"
    assert event.type == "conference"


def test_validate_event_webinar_parses_datetime_with_tz():
    event = validate_event_json(VALID_WEBINAR)
    assert isinstance(event, WebinarEvent)
    assert event.event_id == "webinar-1"
    assert event.type == "webinar"
    assert event.title == "Webinar"
    assert event.description == "Some text"
    assert event.duration_minutes == 60
    # 19:00 MSK == 16:00 UTC
    assert event.datetime.astimezone(timezone.utc) == datetime(2026, 6, 15, 16, 0, tzinfo=timezone.utc)


def test_validate_event_webinar_rejects_naive_datetime():
    raw = b'{"event_id": "w", "type": "webinar", "title": "W", "description": "D", "datetime": "2026-06-15T19:00:00", "duration_minutes": 60}'
    with pytest.raises(ValueError, match="timezone"):
        validate_event_json(raw)


def test_validate_event_webinar_rejects_non_positive_duration():
    raw = b'{"event_id": "w", "type": "webinar", "title": "W", "description": "D", "datetime": "2026-06-15T19:00:00+03:00", "duration_minutes": 0}'
    with pytest.raises(ValueError, match="duration_minutes"):
        validate_event_json(raw)


def test_validate_event_rejects_unknown_type():
    raw = b'{"event_id": "x", "type": "party", "title": "X"}'
    with pytest.raises(ValueError, match="type"):
        validate_event_json(raw)


def test_validate_event_rejects_missing_fields_webinar():
    raw = b'{"event_id": "w", "type": "webinar", "title": "W"}'
    with pytest.raises(ValueError, match="Отсутствуют"):
        validate_event_json(raw)


def test_validate_event_rejects_invalid_json():
    with pytest.raises(ValueError, match="Невалидный JSON"):
        validate_event_json(b"not json {")


def test_load_settings_uses_event_json_env(monkeypatch):
    # Neutralize .env interference so tests exercise env-var logic only
    monkeypatch.setattr("config.load_dotenv", lambda *a, **kw: None)
    monkeypatch.setenv("BOT_TOKEN", "x")
    monkeypatch.setenv("ADMIN_ID", "1")
    monkeypatch.setenv("EVENT_JSON", "custom_event.json")
    monkeypatch.delenv("CONFERENCES_JSON", raising=False)
    s = load_settings()
    assert s.event_json == "custom_event.json"


def test_load_settings_falls_back_to_conferences_json(monkeypatch):
    monkeypatch.setattr("config.load_dotenv", lambda *a, **kw: None)
    monkeypatch.setenv("BOT_TOKEN", "x")
    monkeypatch.setenv("ADMIN_ID", "1")
    monkeypatch.delenv("EVENT_JSON", raising=False)
    monkeypatch.setenv("CONFERENCES_JSON", "old.json")
    s = load_settings()
    assert s.event_json == "old.json"


def test_load_settings_defaults_to_event_json(monkeypatch):
    monkeypatch.setattr("config.load_dotenv", lambda *a, **kw: None)
    monkeypatch.setenv("BOT_TOKEN", "x")
    monkeypatch.setenv("ADMIN_ID", "1")
    monkeypatch.delenv("EVENT_JSON", raising=False)
    monkeypatch.delenv("CONFERENCES_JSON", raising=False)
    s = load_settings()
    assert s.event_json == "event.json"


VALID_IDLE = """
{
  "event_id": "idle-2026-06",
  "type": "idle",
  "title": "Архив"
}
""".encode("utf-8")


def test_validate_event_idle():
    event = validate_event_json(VALID_IDLE)
    assert isinstance(event, IdleEvent)
    assert event.event_id == "idle-2026-06"
    assert event.type == "idle"
    assert event.title == "Архив"


def test_validate_event_idle_rejects_missing_title():
    raw = b'{"event_id": "i", "type": "idle"}'
    with pytest.raises(ValueError, match="Отсутствуют"):
        validate_event_json(raw)


def test_validate_event_idle_rejects_non_string_event_id():
    raw = b'{"event_id": 42, "type": "idle", "title": "X"}'
    with pytest.raises(ValueError, match="event_id"):
        validate_event_json(raw)


def test_load_settings_uses_archive_json_env(monkeypatch):
    monkeypatch.setattr("config.load_dotenv", lambda *a, **kw: None)
    monkeypatch.setenv("BOT_TOKEN", "x")
    monkeypatch.setenv("ADMIN_ID", "1")
    monkeypatch.setenv("ARCHIVE_JSON", "custom_archive.json")
    s = load_settings()
    assert s.archive_json == "custom_archive.json"


def test_load_settings_defaults_archive_json(monkeypatch):
    monkeypatch.setattr("config.load_dotenv", lambda *a, **kw: None)
    monkeypatch.setenv("BOT_TOKEN", "x")
    monkeypatch.setenv("ADMIN_ID", "1")
    monkeypatch.delenv("ARCHIVE_JSON", raising=False)
    s = load_settings()
    assert s.archive_json == "archive.json"
