"""
Unit Tests for Meetings API
Tests for Jitsi Meet integration endpoints
"""
import pytest
from unittest.mock import patch, AsyncMock, MagicMock
from fastapi.testclient import TestClient
from datetime import datetime, timedelta

# Import the app and router
import sys
sys.path.insert(0, '..')

from meetings_api import (
    router,
    generate_room_name,
    generate_password,
    build_jitsi_url,
    MeetingConfig,
    CreateMeetingRequest,
    ScheduleMeetingRequest,
    TrainingRequest,
    ParentTeacherRequest,
    scheduled_meetings,
    active_meetings,
    trainings
)
from fastapi import FastAPI

# Create test app
app = FastAPI()
app.include_router(router)
client = TestClient(app)


class TestHelperFunctions:
    """Test helper functions"""

    def test_generate_room_name_default_prefix(self):
        """Test room name generation with default prefix"""
        room_name = generate_room_name()
        assert room_name.startswith("meeting-")
        assert len(room_name) == len("meeting-") + 8

    def test_generate_room_name_custom_prefix(self):
        """Test room name generation with custom prefix"""
        room_name = generate_room_name("schulung")
        assert room_name.startswith("schulung-")

    def test_generate_room_name_unique(self):
        """Test that room names are unique"""
        names = [generate_room_name() for _ in range(100)]
        assert len(set(names)) == 100

    def test_generate_password(self):
        """Test password generation"""
        password = generate_password()
        assert len(password) == 8
        assert password.isalnum()

    def test_generate_password_unique(self):
        """Test that passwords are unique"""
        passwords = [generate_password() for _ in range(100)]
        assert len(set(passwords)) == 100

    def test_build_jitsi_url_basic(self):
        """Test basic Jitsi URL building"""
        url = build_jitsi_url("test-room")
        assert "localhost:8443/test-room" in url
        assert "config.prejoinPageEnabled=false" in url
        assert "config.defaultLanguage=de" in url

    def test_build_jitsi_url_with_config(self):
        """Test Jitsi URL with config options"""
        config = MeetingConfig(
            start_with_audio_muted=True,
            start_with_video_muted=True,
            require_display_name=True
        )
        url = build_jitsi_url("test-room", config)
        assert "config.startWithAudioMuted=true" in url
        assert "config.startWithVideoMuted=true" in url
        assert "config.requireDisplayName=true" in url

    def test_build_jitsi_url_without_config(self):
        """Test Jitsi URL without config"""
        url = build_jitsi_url("test-room", None)
        assert "localhost:8443/test-room" in url


class TestMeetingStatsEndpoint:
    """Test /stats endpoint"""

    def test_get_stats_empty(self):
        """Test stats with no meetings"""
        # Clear any existing data
        scheduled_meetings.clear()
        active_meetings.clear()

        response = client.get("/api/meetings/stats")
        assert response.status_code == 200

        data = response.json()
        assert "active" in data
        assert "scheduled" in data
        assert "recordings" in data
        assert "participants" in data

    def test_get_stats_with_data(self):
        """Test stats with meetings"""
        scheduled_meetings.clear()
        active_meetings.clear()

        # Add test data
        scheduled_meetings.append({"room_name": "test", "title": "Test"})
        active_meetings.append({"room_name": "active", "title": "Active", "participants": 5})

        response = client.get("/api/meetings/stats")
        assert response.status_code == 200

        data = response.json()
        assert data["scheduled"] == 1
        assert data["active"] == 1
        assert data["participants"] == 5


class TestActiveMeetingsEndpoint:
    """Test /active endpoint"""

    def test_get_active_empty(self):
        """Test active meetings when empty"""
        active_meetings.clear()

        response = client.get("/api/meetings/active")
        assert response.status_code == 200
        assert response.json() == []

    def test_get_active_with_meetings(self):
        """Test active meetings with data"""
        active_meetings.clear()
        active_meetings.append({
            "room_name": "test-room",
            "title": "Test Meeting",
            "participants": 3,
            "started_at": "2025-12-15T10:00:00"
        })

        response = client.get("/api/meetings/active")
        assert response.status_code == 200

        data = response.json()
        assert len(data) == 1
        assert data[0]["room_name"] == "test-room"
        assert data[0]["title"] == "Test Meeting"


class TestCreateMeetingEndpoint:
    """Test /create endpoint"""

    def test_create_quick_meeting(self):
        """Test creating a quick meeting"""
        scheduled_meetings.clear()

        response = client.post("/api/meetings/create", json={
            "type": "quick",
            "title": "Quick Meeting",
            "duration": 30
        })

        assert response.status_code == 200
        data = response.json()
        assert "room_name" in data
        assert data["room_name"].startswith("quick-")
        assert "join_url" in data

    def test_create_scheduled_meeting(self):
        """Test creating a scheduled meeting"""
        scheduled_meetings.clear()

        response = client.post("/api/meetings/create", json={
            "type": "scheduled",
            "title": "Scheduled Meeting",
            "duration": 60,
            "scheduled_at": "2025-12-20T14:00:00"
        })

        assert response.status_code == 200
        data = response.json()
        assert "room_name" in data
        assert "join_url" in data

    def test_create_training_meeting(self):
        """Test creating a training meeting"""
        response = client.post("/api/meetings/create", json={
            "type": "training",
            "title": "Training Session",
            "duration": 120
        })

        assert response.status_code == 200
        data = response.json()
        assert data["room_name"].startswith("schulung-")

    def test_create_parent_meeting(self):
        """Test creating a parent meeting"""
        response = client.post("/api/meetings/create", json={
            "type": "parent",
            "title": "Elterngespraech",
            "duration": 30
        })

        assert response.status_code == 200
        data = response.json()
        assert data["room_name"].startswith("elterngespraech-")

    def test_create_class_meeting(self):
        """Test creating a class meeting"""
        response = client.post("/api/meetings/create", json={
            "type": "class",
            "title": "Klasse 5a",
            "duration": 45
        })

        assert response.status_code == 200
        data = response.json()
        assert data["room_name"].startswith("klasse-")

    def test_create_meeting_with_config(self):
        """Test creating meeting with custom config"""
        response = client.post("/api/meetings/create", json={
            "type": "quick",
            "title": "Configured Meeting",
            "duration": 60,
            "config": {
                "enable_lobby": True,
                "enable_recording": True,
                "start_with_audio_muted": True
            }
        })

        assert response.status_code == 200


class TestScheduleMeetingEndpoint:
    """Test /schedule endpoint"""

    def test_schedule_meeting(self):
        """Test scheduling a meeting"""
        scheduled_meetings.clear()

        response = client.post("/api/meetings/schedule", json={
            "title": "Team Meeting",
            "scheduled_at": "2025-12-20T14:00:00",
            "duration": 60,
            "description": "Weekly team sync"
        })

        assert response.status_code == 200
        data = response.json()
        assert "room_name" in data
        assert "join_url" in data
        assert len(scheduled_meetings) == 1

    def test_schedule_meeting_with_invites(self):
        """Test scheduling with invites"""
        scheduled_meetings.clear()

        response = client.post("/api/meetings/schedule", json={
            "title": "Team Meeting",
            "scheduled_at": "2025-12-20T14:00:00",
            "duration": 60,
            "invites": ["user1@example.com", "user2@example.com"]
        })

        assert response.status_code == 200


class TestTrainingEndpoint:
    """Test /training endpoint"""

    def test_create_training(self):
        """Test creating a training session"""
        trainings.clear()
        scheduled_meetings.clear()

        response = client.post("/api/meetings/training", json={
            "title": "Go Grundlagen",
            "description": "Introduction to Go programming",
            "scheduled_at": "2025-12-20T10:00:00",
            "duration": 120,
            "max_participants": 20,
            "trainer": "Max Mustermann"
        })

        assert response.status_code == 200
        data = response.json()
        assert "schulung-" in data["room_name"]
        assert "go-grundlagen" in data["room_name"].lower()
        assert len(trainings) == 1

    def test_create_training_with_config(self):
        """Test creating training with custom config"""
        trainings.clear()

        response = client.post("/api/meetings/training", json={
            "title": "Docker Workshop",
            "scheduled_at": "2025-12-21T14:00:00",
            "duration": 180,
            "max_participants": 15,
            "trainer": "Lisa Schmidt",
            "config": {
                "enable_recording": True,
                "enable_breakout": True
            }
        })

        assert response.status_code == 200


class TestParentTeacherEndpoint:
    """Test /parent-teacher endpoint"""

    def test_create_parent_teacher_meeting(self):
        """Test creating parent-teacher meeting"""
        scheduled_meetings.clear()

        response = client.post("/api/meetings/parent-teacher", json={
            "student_name": "Max Müller",
            "parent_name": "Herr Müller",
            "parent_email": "mueller@example.com",
            "scheduled_at": "2025-12-18T15:00:00",
            "reason": "Halbjahresgespräch",
            "send_invite": True
        })

        assert response.status_code == 200
        data = response.json()
        assert "elterngespraech-" in data["room_name"]
        assert "max-m" in data["room_name"].lower()
        assert "password" in data
        assert len(data["password"]) == 8

    def test_create_parent_teacher_without_email(self):
        """Test creating without email"""
        response = client.post("/api/meetings/parent-teacher", json={
            "student_name": "Anna Schmidt",
            "parent_name": "Frau Schmidt",
            "scheduled_at": "2025-12-19T14:30:00"
        })

        assert response.status_code == 200


class TestScheduledMeetingsEndpoint:
    """Test /scheduled endpoint"""

    def test_get_scheduled_empty(self):
        """Test getting scheduled meetings when empty"""
        scheduled_meetings.clear()

        response = client.get("/api/meetings/scheduled")
        assert response.status_code == 200
        assert response.json() == []

    def test_get_scheduled_with_data(self):
        """Test getting scheduled meetings with data"""
        scheduled_meetings.clear()
        scheduled_meetings.append({
            "room_name": "test-123",
            "title": "Test Meeting",
            "scheduled_at": "2025-12-20T10:00:00"
        })

        response = client.get("/api/meetings/scheduled")
        assert response.status_code == 200
        assert len(response.json()) == 1


class TestTrainingsEndpoint:
    """Test /trainings endpoint"""

    def test_get_trainings(self):
        """Test getting training sessions"""
        trainings.clear()
        trainings.append({
            "room_name": "schulung-test",
            "title": "Test Training",
            "trainer": "Test Trainer"
        })

        response = client.get("/api/meetings/trainings")
        assert response.status_code == 200
        assert len(response.json()) == 1


class TestDeleteMeetingEndpoint:
    """Test DELETE endpoint"""

    def test_delete_meeting(self):
        """Test deleting a meeting"""
        # Clear and add a single meeting
        scheduled_meetings.clear()
        scheduled_meetings.append({
            "room_name": "to-delete",
            "title": "Delete Me"
        })
        initial_count = len(scheduled_meetings)

        response = client.delete("/api/meetings/to-delete")
        assert response.status_code == 200
        assert response.json()["status"] == "deleted"
        # Check that meeting was removed
        assert len([m for m in scheduled_meetings if m["room_name"] == "to-delete"]) == 0

    def test_delete_nonexistent_meeting(self):
        """Test deleting a non-existent meeting"""
        initial_count = len(scheduled_meetings)

        response = client.delete("/api/meetings/nonexistent")
        assert response.status_code == 200
        # Count should remain the same (nothing was deleted)
        assert len(scheduled_meetings) == initial_count


class TestRecordingsEndpoints:
    """Test recordings endpoints"""

    def test_get_recordings(self):
        """Test getting recordings list"""
        response = client.get("/api/meetings/recordings")
        assert response.status_code == 200

        data = response.json()
        assert isinstance(data, list)
        assert len(data) > 0

    def test_get_recording_details(self):
        """Test getting recording details"""
        response = client.get("/api/meetings/recordings/docker-basics")
        assert response.status_code == 200

        data = response.json()
        assert data["id"] == "docker-basics"
        assert "title" in data
        assert "download_url" in data

    def test_download_recording_demo_mode(self):
        """Test download in demo mode returns 404"""
        response = client.get("/api/meetings/recordings/test/download")
        assert response.status_code == 404

    def test_delete_recording(self):
        """Test deleting a recording"""
        response = client.delete("/api/meetings/recordings/test-recording")
        assert response.status_code == 200
        assert response.json()["status"] == "deleted"


class TestHealthEndpoint:
    """Test health check endpoint"""

    @patch('meetings_api.httpx.AsyncClient')
    def test_health_check_jitsi_available(self, mock_client):
        """Test health check when Jitsi is available"""
        # Skip this test as it requires async mocking
        pass

    def test_health_check_returns_status(self):
        """Test health check returns expected fields"""
        response = client.get("/api/meetings/health")
        assert response.status_code == 200

        data = response.json()
        assert "status" in data
        assert "jitsi_url" in data
        assert "jitsi_available" in data
        assert "scheduled_meetings" in data
        assert "active_meetings" in data


class TestMeetingConfigModel:
    """Test MeetingConfig model"""

    def test_default_config(self):
        """Test default config values"""
        config = MeetingConfig()
        assert config.enable_lobby is True
        assert config.enable_recording is False
        assert config.start_with_audio_muted is True
        assert config.start_with_video_muted is False
        assert config.require_display_name is True
        assert config.enable_breakout is False

    def test_custom_config(self):
        """Test custom config values"""
        config = MeetingConfig(
            enable_lobby=False,
            enable_recording=True,
            enable_breakout=True
        )
        assert config.enable_lobby is False
        assert config.enable_recording is True
        assert config.enable_breakout is True


class TestRequestModels:
    """Test request models"""

    def test_create_meeting_request_defaults(self):
        """Test CreateMeetingRequest defaults"""
        request = CreateMeetingRequest()
        assert request.type == "quick"
        assert request.title == "Neues Meeting"
        assert request.duration == 60
        assert request.scheduled_at is None
        assert request.config is None

    def test_schedule_meeting_request(self):
        """Test ScheduleMeetingRequest"""
        request = ScheduleMeetingRequest(
            title="Test",
            scheduled_at="2025-12-20T10:00:00"
        )
        assert request.title == "Test"
        assert request.duration == 60

    def test_training_request(self):
        """Test TrainingRequest"""
        request = TrainingRequest(
            title="Test Training",
            scheduled_at="2025-12-20T10:00:00",
            trainer="Trainer"
        )
        assert request.title == "Test Training"
        assert request.duration == 120
        assert request.max_participants == 20

    def test_parent_teacher_request(self):
        """Test ParentTeacherRequest"""
        request = ParentTeacherRequest(
            student_name="Max",
            parent_name="Herr Müller",
            scheduled_at="2025-12-20T10:00:00"
        )
        assert request.student_name == "Max"
        assert request.duration == 30
        assert request.send_invite is True
