"""
Unit tests for streams app models.
"""

import tempfile
import shutil
from datetime import timedelta
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.utils import timezone

from apps.streams.models import (
    Channel, StreamSession, HLSSegment, 
    VideoConfiguration, AudioConfiguration
)

User = get_user_model()


class ChannelModelTest(TestCase):
    """Test cases for Channel model."""
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        self.temp_dir = tempfile.mkdtemp()
    
    def tearDown(self):
        shutil.rmtree(self.temp_dir, ignore_errors=True)
    
    def test_channel_creation(self):
        """Test basic channel creation."""
        channel = Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream.m3u8',
            output_directory=self.temp_dir,
            created_by=self.user
        )
        
        self.assertEqual(channel.name, 'Test Channel')
        self.assertEqual(channel.slug, 'test-channel')
        self.assertEqual(channel.segment_duration, 6)  # Default value
        self.assertEqual(channel.max_segments, 10)  # Default value
        self.assertTrue(channel.is_active)  # Default value
    
    def test_channel_unique_constraints(self):
        """Test unique constraints on name and slug."""
        Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream1.m3u8',
            output_directory=self.temp_dir,
            created_by=self.user
        )
        
        # Test duplicate name
        with self.assertRaises(Exception):
            Channel.objects.create(
                name='Test Channel',
                slug='test-channel-2',
                hls_url='https://example.com/stream2.m3u8',
                output_directory=self.temp_dir,
                created_by=self.user
            )
        
        # Test duplicate slug
        with self.assertRaises(Exception):
            Channel.objects.create(
                name='Test Channel 2',
                slug='test-channel',
                hls_url='https://example.com/stream3.m3u8',
                output_directory=self.temp_dir,
                created_by=self.user
            )
    
    def test_get_output_path(self):
        """Test output path generation."""
        channel = Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream.m3u8',
            output_directory='/tmp/streams',
            created_by=self.user
        )
        
        output_path = channel.get_output_path()
        expected_path = f'/tmp/streams/{channel.slug}'
        self.assertEqual(output_path, expected_path)
    
    def test_get_active_session(self):
        """Test active session retrieval."""
        channel = Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream.m3u8',
            output_directory=self.temp_dir,
            created_by=self.user
        )
        
        # No active session initially
        self.assertIsNone(channel.get_active_session())
        
        # Create active session
        session = StreamSession.objects.create(
            channel=channel,
            status='active',
            started_at=timezone.now()
        )
        
        # Should return the active session
        self.assertEqual(channel.get_active_session(), session)


class StreamSessionModelTest(TestCase):
    """Test cases for StreamSession model."""
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        self.channel = Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream.m3u8',
            output_directory='/tmp/test',
            created_by=self.user
        )
    
    def test_session_creation(self):
        """Test basic session creation."""
        session = StreamSession.objects.create(
            channel=self.channel,
            status='pending',
            started_at=timezone.now()
        )
        
        self.assertEqual(session.channel, self.channel)
        self.assertEqual(session.status, 'pending')
        self.assertIsNotNone(session.started_at)
        self.assertIsNone(session.ended_at)
    
    def test_session_duration(self):
        """Test session duration calculation."""
        start_time = timezone.now()
        session = StreamSession.objects.create(
            channel=self.channel,
            status='active',
            started_at=start_time
        )
        
        # Active session - duration should be from start to now
        duration = session.duration()
        self.assertIsNotNone(duration)
        self.assertGreater(duration.total_seconds(), 0)
        
        # Completed session
        end_time = start_time + timedelta(minutes=30)
        session.ended_at = end_time
        session.status = 'completed'
        session.save()
        
        duration = session.duration()
        self.assertEqual(duration, timedelta(minutes=30))
    
    def test_session_str_representation(self):
        """Test string representation of session."""
        session = StreamSession.objects.create(
            channel=self.channel,
            status='active',
            started_at=timezone.now()
        )
        
        expected_str = f"Session {session.id} - {self.channel.name} (active)"
        self.assertEqual(str(session), expected_str)


class HLSSegmentModelTest(TestCase):
    """Test cases for HLSSegment model."""
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
        self.channel = Channel.objects.create(
            name='Test Channel',
            slug='test-channel',
            hls_url='https://example.com/stream.m3u8',
            output_directory='/tmp/test',
            created_by=self.user
        )
        self.session = StreamSession.objects.create(
            channel=self.channel,
            status='active',
            started_at=timezone.now()
        )
    
    def test_segment_creation(self):
        """Test basic segment creation."""
        segment = HLSSegment.objects.create(
            session=self.session,
            sequence_number=1,
            filename='segment_001.ts',
            file_path='/tmp/test/segment_001.ts',
            duration=6.0,
            file_size=1024000
        )
        
        self.assertEqual(segment.session, self.session)
        self.assertEqual(segment.sequence_number, 1)
        self.assertEqual(segment.filename, 'segment_001.ts')
        self.assertEqual(segment.duration, 6.0)
        self.assertFalse(segment.is_processed)  # Default value
    
    def test_segment_ordering(self):
        """Test segment ordering by sequence number."""
        # Create segments out of order
        segment2 = HLSSegment.objects.create(
            session=self.session,
            sequence_number=2,
            filename='segment_002.ts',
            file_path='/tmp/test/segment_002.ts',
            duration=6.0
        )
        
        segment1 = HLSSegment.objects.create(
            session=self.session,
            sequence_number=1,
            filename='segment_001.ts',
            file_path='/tmp/test/segment_001.ts',
            duration=6.0
        )
        
        # Should be ordered by sequence number
        segments = list(HLSSegment.objects.filter(session=self.session))
        self.assertEqual(segments[0], segment1)
        self.assertEqual(segments[1], segment2)


class VideoConfigurationModelTest(TestCase):
    """Test cases for VideoConfiguration model."""
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_video_config_creation(self):
        """Test video configuration creation."""
        config = VideoConfiguration.objects.create(
            name='HD Config',
            codec='h264',
            bitrate=2000000,
            width=1920,
            height=1080,
            framerate=30.0,
            created_by=self.user
        )
        
        self.assertEqual(config.name, 'HD Config')
        self.assertEqual(config.codec, 'h264')
        self.assertEqual(config.bitrate, 2000000)
        self.assertEqual(config.width, 1920)
        self.assertEqual(config.height, 1080)
        self.assertEqual(config.framerate, 30.0)
    
    def test_video_config_validation(self):
        """Test video configuration validation."""
        # Test invalid framerate
        with self.assertRaises(ValidationError):
            config = VideoConfiguration(
                name='Invalid Config',
                codec='h264',
                bitrate=2000000,
                width=1920,
                height=1080,
                framerate=0,  # Invalid
                created_by=self.user
            )
            config.full_clean()
        
        # Test invalid dimensions
        with self.assertRaises(ValidationError):
            config = VideoConfiguration(
                name='Invalid Config',
                codec='h264',
                bitrate=2000000,
                width=0,  # Invalid
                height=1080,
                framerate=30.0,
                created_by=self.user
            )
            config.full_clean()


class AudioConfigurationModelTest(TestCase):
    """Test cases for AudioConfiguration model."""
    
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123'
        )
    
    def test_audio_config_creation(self):
        """Test audio configuration creation."""
        config = AudioConfiguration.objects.create(
            name='High Quality Audio',
            codec='aac',
            bitrate=128000,
            sample_rate=44100,
            channels=2,
            created_by=self.user
        )
        
        self.assertEqual(config.name, 'High Quality Audio')
        self.assertEqual(config.codec, 'aac')
        self.assertEqual(config.bitrate, 128000)
        self.assertEqual(config.sample_rate, 44100)
        self.assertEqual(config.channels, 2)
    
    def test_audio_config_validation(self):
        """Test audio configuration validation."""
        # Test invalid sample rate
        with self.assertRaises(ValidationError):
            config = AudioConfiguration(
                name='Invalid Config',
                codec='aac',
                bitrate=128000,
                sample_rate=0,  # Invalid
                channels=2,
                created_by=self.user
            )
            config.full_clean()
        
        # Test invalid channels
        with self.assertRaises(ValidationError):
            config = AudioConfiguration(
                name='Invalid Config',
                codec='aac',
                bitrate=128000,
                sample_rate=44100,
                channels=0,  # Invalid
                created_by=self.user
            )
            config.full_clean()
