# Generated by Django 5.2.4 on 2025-07-22 12:08

import django.core.validators
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Channel',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('name', models.CharField(help_text='Full official name of the television channel', max_length=200, verbose_name='Channel Name')),
                ('display_name', models.CharField(help_text='Official call sign or short identifier (e.g., "WABC-TV", "ESPN")', max_length=20, unique=True, verbose_name='Call Sign')),
                ('channel_number', models.CharField(help_text='Channel number in cable/satellite listings (e.g., "7.1", "ESPN")', max_length=20, verbose_name='Channel Number')),
                ('channel_type', models.CharField(choices=[('terrestrial', 'Terrestrial/Over-the-Air'), ('cable', 'Cable Channel'), ('satellite', 'Satellite Channel'), ('iptv', 'IPTV Channel'), ('streaming', 'Streaming Channel'), ('radio', 'Radio Station')], default='satellite', help_text='Broadcasting technology and distribution method', max_length=20, verbose_name='Channel Type')),
                ('status', models.CharField(choices=[('active', 'Active'), ('inactive', 'Inactive'), ('maintenance', 'Maintenance'), ('testing', 'Testing')], default='active', help_text='Current operational status of the channel', max_length=20, verbose_name='Channel Status')),
                ('logo', models.ImageField(blank=True, help_text='Channel logo or branding image', null=True, upload_to='channels/logos/', verbose_name='Channel Logo')),
                ('description', models.TextField(blank=True, help_text='Brief description of the channel and its content', verbose_name='Channel Description')),
                ('website', models.URLField(blank=True, help_text="Channel's official website URL", verbose_name='Official Website')),
                ('language', models.CharField(blank=True, help_text='Primary language of broadcast content', max_length=250, verbose_name='Primary Language')),
                ('category', models.CharField(blank=True, help_text='Primary content category (News, Sports, Entertainment, etc.)', max_length=250, verbose_name='Content Category')),
                ('target_audience', models.CharField(blank=True, help_text='Primary target demographic (Children, Adults, Seniors, etc.)', max_length=100, verbose_name='Target Audience')),
                ('supports_dai', models.BooleanField(default=True, help_text='Whether the channel supports Dynamic Ad Insertion', verbose_name='Supports DAI')),
                ('last_health_check', models.DateTimeField(blank=True, help_text='Timestamp of the most recent health monitoring check', null=True, verbose_name='Last Health Check')),
                ('is_online', models.BooleanField(default=True, help_text='Current online/offline status of the channel', verbose_name='Is Online')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Channel',
                'verbose_name_plural': 'Channels',
                'db_table': 'channels',
                'ordering': ['channel_number', 'name'],
            },
        ),
        migrations.CreateModel(
            name='ChannelCodec',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('name', models.CharField(help_text='Human-readable name for this codec configuration', max_length=100, verbose_name='Codec Name')),
                ('video_codec', models.CharField(help_text='Video codec identifier (h264, h265, vp9, etc.)', max_length=50, verbose_name='Video Codec')),
                ('audio_codec', models.CharField(help_text='Audio codec identifier (aac, mp3, opus, etc.)', max_length=50, verbose_name='Audio Codec')),
                ('resolution', models.CharField(blank=True, help_text='Video resolution in WIDTHxHEIGHT format (e.g., 1920x1080)', max_length=20, verbose_name='Resolution')),
                ('bitrate', models.PositiveIntegerField(help_text='Target bitrate in kbps', verbose_name='Bitrate')),
                ('frame_rate', models.DecimalField(blank=True, decimal_places=2, help_text='Target frame rate in fps (e.g., 29.97, 25.00)', max_digits=5, null=True, verbose_name='Frame Rate')),
                ('ffmpeg_options', models.JSONField(blank=True, default=dict, help_text='Additional FFmpeg encoding options as JSON object', verbose_name='FFmpeg Options')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Channel Codec',
                'verbose_name_plural': 'Channel Codecs',
                'db_table': 'channel_codecs',
                'ordering': ['name'],
            },
        ),
        migrations.CreateModel(
            name='ChannelZone',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('name', models.CharField(help_text='Human-readable name of the geographic zone', max_length=255, verbose_name='Zone Name')),
                ('code', models.CharField(help_text='Unique identifier code for the zone (e.g., "NAE", "EUR")', max_length=10, unique=True, verbose_name='Zone Code')),
                ('description', models.TextField(blank=True, help_text='Optional detailed description of the zone coverage', verbose_name='Description')),
                ('timezone', models.CharField(default='UTC', help_text='Timezone identifier (e.g., "America/New_York", "Europe/London")', max_length=50, verbose_name='Timezone')),
                ('is_active', models.BooleanField(default=True, help_text='Whether this zone is currently accepting broadcasts', verbose_name='Is Active')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Channel Zone',
                'verbose_name_plural': 'Channel Zones',
                'db_table': 'channel_zones',
                'ordering': ['name'],
            },
        ),
        migrations.CreateModel(
            name='ChannelZoneRelation',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('stream_url', models.URLField(blank=True, help_text='Custom streaming URL for this zone', verbose_name='Zone-specific Stream URL')),
                ('backup_stream_url', models.URLField(blank=True, help_text='Secondary URL for failover streaming', verbose_name='Zone-specific Backup Stream URL')),
                ('ftp_host', models.CharField(blank=True, help_text='FTP server hostname or IP address for content delivery', max_length=255, verbose_name='FTP Host')),
                ('ftp_username', models.CharField(blank=True, help_text='Username for FTP authentication', max_length=100, verbose_name='FTP Username')),
                ('ftp_password', models.CharField(blank=True, help_text='Password for FTP authentication', max_length=255, verbose_name='FTP Password')),
                ('ftp_port', models.PositiveIntegerField(default=21, help_text='FTP server port number (default: 21)', verbose_name='FTP Port')),
                ('ftp_root_directory', models.CharField(blank=True, default='/', help_text='Root directory path on the FTP server', max_length=500, verbose_name='FTP Root Directory')),
                ('ftp_use_passive', models.BooleanField(default=True, help_text='Whether to use passive mode for FTP connections', verbose_name='Use FTP Passive Mode')),
                ('vpn_type', models.CharField(choices=[('none', 'No VPN'), ('ipsec', 'IPSec Tunnel'), ('openvpn', 'OpenVPN'), ('wireguard', 'WireGuard')], default='none', help_text='Type of VPN connection for secure streaming', max_length=20, verbose_name='VPN Type')),
                ('vpn_server_address', models.CharField(blank=True, help_text='VPN server IP address or hostname', max_length=255, verbose_name='VPN Server Address')),
                ('vpn_username', models.CharField(blank=True, help_text='Username for VPN authentication', max_length=100, verbose_name='VPN Username')),
                ('vpn_password', models.CharField(blank=True, help_text='Password for VPN authentication', max_length=255, verbose_name='VPN Password')),
                ('is_active', models.BooleanField(default=True, help_text='Whether this channel is active in this zone', verbose_name='Active in Zone')),
                ('priority', models.PositiveIntegerField(default=1, help_text='Priority level for this zone (higher number = higher priority)', verbose_name='Priority')),
                ('channel', models.ForeignKey(help_text='The channel this configuration applies to', on_delete=django.db.models.deletion.CASCADE, related_name='zone_relations', to='channels.channel', verbose_name='Channel')),
                ('codec', models.ForeignKey(blank=True, help_text='Override codec configuration for this zone', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='zone_relations', to='channels.channelcodec', verbose_name='Zone-specific Codec')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
                ('zone', models.ForeignKey(help_text='The geographic zone this configuration is for', on_delete=django.db.models.deletion.CASCADE, related_name='channel_relations', to='channels.channelzone', verbose_name='Zone')),
            ],
            options={
                'verbose_name': 'Channel Zone Relation',
                'verbose_name_plural': 'Channel Zone Relations',
                'db_table': 'channel_zone_relations',
                'ordering': ['channel', 'zone', '-priority'],
            },
        ),
        migrations.AddField(
            model_name='channel',
            name='zones',
            field=models.ManyToManyField(blank=True, help_text='Geographic zones where this channel is available', related_name='channels', through='channels.ChannelZoneRelation', to='channels.channelzone', verbose_name='Broadcasting Zones'),
        ),
        migrations.CreateModel(
            name='EPGProgram',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('title', models.CharField(help_text='Full title of the program', max_length=255, verbose_name='Program Title')),
                ('description', models.TextField(blank=True, help_text='Detailed description of the program content', verbose_name='Program Description')),
                ('program_type', models.CharField(choices=[('movie', 'Movie'), ('series', 'TV Series'), ('news', 'News'), ('sports', 'Sports'), ('documentary', 'Documentary'), ('entertainment', 'Entertainment'), ('kids', 'Kids'), ('music', 'Music'), ('other', 'Other')], default='other', help_text='Category classification of the program', max_length=20, verbose_name='Program Type')),
                ('start_time', models.DateTimeField(help_text='When the program starts broadcasting', verbose_name='Start Time')),
                ('end_time', models.DateTimeField(help_text='When the program ends broadcasting', verbose_name='End Time')),
                ('duration', models.PositiveIntegerField(help_text='Program duration in minutes', verbose_name='Duration')),
                ('season_number', models.PositiveIntegerField(blank=True, help_text='Season number for series content', null=True, verbose_name='Season Number')),
                ('episode_number', models.PositiveIntegerField(blank=True, help_text='Episode number within the season', null=True, verbose_name='Episode Number')),
                ('original_air_date', models.DateField(blank=True, help_text='Original broadcast date of this content', null=True, verbose_name='Original Air Date')),
                ('content_rating', models.CharField(blank=True, help_text='Age/content rating (G, PG, PG-13, R, etc.)', max_length=10, verbose_name='Content Rating')),
                ('language', models.CharField(blank=True, help_text='Primary language of the program', max_length=50, verbose_name='Language')),
                ('subtitles_available', models.BooleanField(default=False, help_text='Whether closed captions/subtitles are available', verbose_name='Subtitles Available')),
                ('has_ad_breaks', models.BooleanField(default=True, help_text='Whether this program supports commercial breaks', verbose_name='Has Ad Breaks')),
                ('ad_break_positions', models.JSONField(blank=True, default=list, help_text='List of timestamps (in seconds) where ads can be inserted', verbose_name='Ad Break Positions')),
                ('channel', models.ForeignKey(help_text='Channel broadcasting this program', on_delete=django.db.models.deletion.CASCADE, related_name='programs', to='channels.channel', verbose_name='Channel')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'EPG Program',
                'verbose_name_plural': 'EPG Programs',
                'db_table': 'epg_programs',
                'ordering': ['channel', 'start_time'],
            },
        ),
        migrations.CreateModel(
            name='IPSecConfiguration',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('is_enabled', models.BooleanField(default=True, help_text='Whether this VPN configuration is currently enabled', verbose_name='Is Enabled')),
                ('preshared_key', models.TextField(help_text='IPSec pre-shared key for authentication', verbose_name='Pre-shared Key')),
                ('local_subnet', models.CharField(help_text='Local network subnet in CIDR notation (e.g., 192.168.1.0/24)', max_length=18, validators=[django.core.validators.RegexValidator(message='Enter a valid CIDR subnet (e.g., 192.168.1.0/24)', regex='^(\\d{1,3}\\.){3}\\d{1,3}/\\d{1,2}$')], verbose_name='Local Subnet')),
                ('remote_subnet', models.CharField(help_text='Remote network subnet in CIDR notation (e.g., 10.0.0.0/24)', max_length=18, validators=[django.core.validators.RegexValidator(message='Enter a valid CIDR subnet (e.g., 10.0.0.0/24)', regex='^(\\d{1,3}\\.){3}\\d{1,3}/\\d{1,2}$')], verbose_name='Remote Subnet')),
                ('encryption_algorithm', models.CharField(choices=[('aes128', 'AES-128'), ('aes192', 'AES-192'), ('aes256', 'AES-256'), ('3des', '3DES')], default='aes256', help_text='Encryption algorithm for IPSec tunnel', max_length=20, verbose_name='Encryption Algorithm')),
                ('hash_algorithm', models.CharField(choices=[('sha1', 'SHA-1'), ('sha256', 'SHA-256'), ('sha384', 'SHA-384'), ('sha512', 'SHA-512'), ('md5', 'MD5')], default='sha256', help_text='Hash algorithm for integrity verification', max_length=20, verbose_name='Hash Algorithm')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
                ('zone_relation', models.OneToOneField(help_text='The zone relation this VPN configuration applies to', on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_config', to='channels.channelzonerelation', verbose_name='Zone Relation')),
            ],
            options={
                'verbose_name': 'IPSec Configuration',
                'verbose_name_plural': 'IPSec Configurations',
                'db_table': 'ipsec_configurations',
            },
        ),
        migrations.CreateModel(
            name='Jingle',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('name', models.CharField(help_text='Human-readable name for this jingle', max_length=255, verbose_name='Jingle Name')),
                ('jingle_type', models.CharField(choices=[('station_id', 'Station ID'), ('bumper', 'Bumper'), ('promo', 'Promo'), ('transition', 'Transition'), ('commercial_break', 'Commercial Break')], help_text='Type of jingle content', max_length=20, verbose_name='Jingle Type')),
                ('placement_type', models.CharField(choices=[('start', 'Start of Show'), ('end', 'End of Show'), ('commercial_start', 'Start of Commercial Break'), ('commercial_end', 'End of Commercial Break'), ('program_transition', 'Program Transition'), ('hourly', 'Hourly'), ('half_hourly', 'Half Hourly'), ('random', 'Random Placement')], default='random', help_text='When this jingle should be played in the broadcast', max_length=20, verbose_name='Placement Type')),
                ('file', models.FileField(help_text='Audio file for this jingle', upload_to='jingles/', verbose_name='Audio File')),
                ('duration', models.PositiveIntegerField(help_text='Duration of the jingle in seconds', verbose_name='Duration')),
                ('audio_fingerprint', models.TextField(blank=True, help_text='Audio fingerprint data for automatic detection in streams', verbose_name='Audio Fingerprint')),
                ('video_fingerprint', models.TextField(blank=True, help_text='Video fingerprint data for automatic detection in streams', verbose_name='Video Fingerprint')),
                ('is_active', models.BooleanField(default=True, help_text='Whether this jingle is currently active', verbose_name='Is Active')),
                ('priority', models.PositiveIntegerField(default=1, help_text='Priority level for jingle selection (higher number = higher priority)', verbose_name='Priority')),
                ('start_date', models.DateField(blank=True, help_text='Optional start date for when this jingle becomes active', null=True, verbose_name='Start Date')),
                ('end_date', models.DateField(blank=True, help_text='Optional end date for when this jingle becomes inactive', null=True, verbose_name='End Date')),
                ('time_slots', models.JSONField(blank=True, default=list, help_text='JSON list of time ranges when this jingle can play', verbose_name='Time Slots')),
                ('play_count', models.PositiveIntegerField(default=0, help_text='Number of times this jingle has been played', verbose_name='Play Count')),
                ('last_played', models.DateTimeField(blank=True, help_text='Timestamp of when this jingle was last played', null=True, verbose_name='Last Played')),
                ('channel', models.ForeignKey(help_text='Channel this jingle belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='jingles', to='channels.channel', verbose_name='Channel')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Jingle',
                'verbose_name_plural': 'Jingles',
                'db_table': 'jingles',
                'ordering': ['channel', '-priority', 'name'],
            },
        ),
        migrations.CreateModel(
            name='JingleDetection',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('detected_at', models.DateTimeField(auto_now_add=True, help_text='When the detection was recorded in the system', verbose_name='Detected At')),
                ('start_timestamp', models.DateTimeField(help_text='When the jingle started playing in the stream', verbose_name='Start Time')),
                ('end_timestamp', models.DateTimeField(help_text='When the jingle ended playing in the stream', verbose_name='End Time')),
                ('confidence_score', models.DecimalField(decimal_places=4, help_text='Detection confidence score from 0.0 to 1.0', max_digits=5, verbose_name='Confidence Score')),
                ('detection_method', models.CharField(choices=[('audio_fingerprint', 'Audio Fingerprint'), ('video_fingerprint', 'Video Fingerprint'), ('combined', 'Combined Audio/Video'), ('manual', 'Manual Detection')], default='audio_fingerprint', help_text='Method used for detection', max_length=50, verbose_name='Detection Method')),
                ('stream_position', models.PositiveIntegerField(help_text='Position in stream where jingle was detected (seconds from start)', verbose_name='Stream Position')),
                ('status', models.CharField(choices=[('detected', 'Detected'), ('confirmed', 'Confirmed'), ('false_positive', 'False Positive')], default='detected', help_text='Validation status of this detection', max_length=20, verbose_name='Status')),
                ('metadata', models.JSONField(blank=True, default=dict, help_text='Additional detection metadata and parameters', verbose_name='Metadata')),
                ('channel', models.ForeignKey(help_text='Channel where the jingle was detected', on_delete=django.db.models.deletion.CASCADE, related_name='jingle_detections', to='channels.channel', verbose_name='Channel')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('jingle', models.ForeignKey(help_text='The jingle that was detected', on_delete=django.db.models.deletion.CASCADE, related_name='detections', to='channels.jingle', verbose_name='Jingle')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Jingle Detection',
                'verbose_name_plural': 'Jingle Detections',
                'db_table': 'jingle_detections',
                'ordering': ['-detected_at'],
            },
        ),
        migrations.CreateModel(
            name='OpenVPNConfiguration',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('is_enabled', models.BooleanField(default=True, help_text='Whether this VPN configuration is currently enabled', verbose_name='Is Enabled')),
                ('config_file', models.FileField(blank=True, help_text='OpenVPN configuration file (.ovpn)', null=True, upload_to='vpn_configs/openvpn/', verbose_name='OpenVPN Config File')),
                ('ca_cert', models.TextField(blank=True, help_text='Certificate Authority certificate in PEM format', verbose_name='CA Certificate')),
                ('client_cert', models.TextField(blank=True, help_text='Client certificate in PEM format', verbose_name='Client Certificate')),
                ('client_key', models.TextField(blank=True, help_text='Client private key in PEM format', verbose_name='Client Private Key')),
                ('compression', models.CharField(choices=[('none', 'No Compression'), ('lzo', 'LZO Compression'), ('lz4', 'LZ4 Compression')], default='lzo', help_text='Compression algorithm for OpenVPN tunnel', max_length=20, verbose_name='Compression')),
                ('cipher', models.CharField(choices=[('aes-256-cbc', 'AES-256-CBC'), ('aes-192-cbc', 'AES-192-CBC'), ('aes-128-cbc', 'AES-128-CBC'), ('aes-256-gcm', 'AES-256-GCM'), ('chacha20-poly1305', 'ChaCha20-Poly1305')], default='aes-256-cbc', help_text='Encryption cipher for OpenVPN tunnel', max_length=30, verbose_name='Cipher')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
                ('zone_relation', models.OneToOneField(help_text='The zone relation this VPN configuration applies to', on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_config', to='channels.channelzonerelation', verbose_name='Zone Relation')),
            ],
            options={
                'verbose_name': 'OpenVPN Configuration',
                'verbose_name_plural': 'OpenVPN Configurations',
                'db_table': 'openvpn_configurations',
            },
        ),
        migrations.CreateModel(
            name='WireGuardConfiguration',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('is_enabled', models.BooleanField(default=True, help_text='Whether this VPN configuration is currently enabled', verbose_name='Is Enabled')),
                ('private_key', models.TextField(help_text='WireGuard private key for this client', verbose_name='Private Key')),
                ('public_key', models.TextField(blank=True, help_text='WireGuard public key for this client (auto-generated from private key)', verbose_name='Public Key')),
                ('peer_public_key', models.TextField(help_text='WireGuard public key of the VPN server', verbose_name='Peer Public Key')),
                ('endpoint', models.CharField(help_text='WireGuard server endpoint (host:port, e.g., vpn.example.com:51820)', max_length=255, verbose_name='Endpoint')),
                ('allowed_ips', models.TextField(default='0.0.0.0/0', help_text='Comma-separated list of allowed IP ranges (CIDR notation)', verbose_name='Allowed IPs')),
                ('persistent_keepalive', models.PositiveIntegerField(default=25, help_text='Keepalive interval in seconds (0 to disable)', verbose_name='Persistent Keepalive')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
                ('zone_relation', models.OneToOneField(help_text='The zone relation this VPN configuration applies to', on_delete=django.db.models.deletion.CASCADE, related_name='%(class)s_config', to='channels.channelzonerelation', verbose_name='Zone Relation')),
            ],
            options={
                'verbose_name': 'WireGuard Configuration',
                'verbose_name_plural': 'WireGuard Configurations',
                'db_table': 'wireguard_configurations',
            },
        ),
        migrations.CreateModel(
            name='ChannelSchedule',
            fields=[
                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Timestamp when this object was created', verbose_name='Created At')),
                ('updated_at', models.DateTimeField(auto_now=True, help_text='Timestamp when this object was last modified', verbose_name='Updated At')),
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for this object', primary_key=True, serialize=False)),
                ('is_deleted', models.BooleanField(default=False, help_text='Whether this object has been soft-deleted', verbose_name='Is Deleted')),
                ('deleted_at', models.DateTimeField(blank=True, help_text='Timestamp when this object was soft-deleted', null=True, verbose_name='Deleted At')),
                ('title', models.CharField(help_text='Title or name for this schedule entry', max_length=255, verbose_name='Schedule Title')),
                ('schedule_type', models.CharField(choices=[('regular', 'Regular Programming'), ('special', 'Special Event'), ('maintenance', 'Maintenance'), ('test', 'Test Broadcast'), ('emergency', 'Emergency Broadcast'), ('replay', 'Replay/Rerun')], default='regular', help_text='Type of scheduled content or event', max_length=20, verbose_name='Schedule Type')),
                ('start_time', models.DateTimeField(help_text='When this schedule entry begins', verbose_name='Start Time')),
                ('end_time', models.DateTimeField(help_text='When this schedule entry ends', verbose_name='End Time')),
                ('description', models.TextField(blank=True, help_text='Detailed description of the scheduled content', verbose_name='Description')),
                ('content_url', models.URLField(blank=True, help_text='Primary URL for the scheduled content stream', verbose_name='Content URL')),
                ('backup_content_url', models.URLField(blank=True, help_text='Backup URL for content streaming', verbose_name='Backup Content URL')),
                ('allow_ads', models.BooleanField(default=True, help_text='Whether ads can be inserted during this schedule', verbose_name='Allow Advertisements')),
                ('ad_break_duration', models.PositiveIntegerField(default=120, help_text='Duration of advertisement breaks in seconds', verbose_name='Ad Break Duration')),
                ('is_active', models.BooleanField(default=True, help_text='Whether this schedule entry is currently active', verbose_name='Active')),
                ('priority', models.PositiveIntegerField(default=1, help_text='Schedule priority (higher number = higher priority)', verbose_name='Priority')),
                ('notify_before_minutes', models.PositiveIntegerField(default=30, help_text='Minutes before start time to send notifications', verbose_name='Notification Lead Time')),
                ('channel', models.ForeignKey(help_text='Channel for this schedule entry', on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='channels.channel', verbose_name='Channel')),
                ('created_by', models.ForeignKey(blank=True, help_text='User who created this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
                ('deleted_by', models.ForeignKey(blank=True, help_text='User who soft-deleted this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_deleted', to=settings.AUTH_USER_MODEL, verbose_name='Deleted By')),
                ('updated_by', models.ForeignKey(blank=True, help_text='User who last modified this object', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL, verbose_name='Updated By')),
            ],
            options={
                'verbose_name': 'Channel Schedule',
                'verbose_name_plural': 'Channel Schedules',
                'db_table': 'channel_schedules',
                'ordering': ['channel', 'start_time', '-priority'],
                'indexes': [models.Index(fields=['channel', 'start_time'], name='schedule_channel_start_idx'), models.Index(fields=['schedule_type'], name='schedule_type_idx'), models.Index(fields=['is_active', 'start_time'], name='schedule_active_start_idx')],
                'constraints': [models.CheckConstraint(condition=models.Q(('end_time__gt', models.F('start_time'))), name='schedule_valid_time_range'), models.CheckConstraint(condition=models.Q(('priority__gte', 1)), name='schedule_positive_priority')],
            },
        ),
        migrations.AddIndex(
            model_name='channelzonerelation',
            index=models.Index(fields=['channel', 'zone'], name='channel_zon_channel_35e2ee_idx'),
        ),
        migrations.AddIndex(
            model_name='channelzonerelation',
            index=models.Index(fields=['zone', 'is_active'], name='channel_zon_zone_id_c83795_idx'),
        ),
        migrations.AddIndex(
            model_name='channelzonerelation',
            index=models.Index(fields=['channel', 'is_active', 'priority'], name='channel_zon_channel_01b275_idx'),
        ),
        migrations.AlterUniqueTogether(
            name='channelzonerelation',
            unique_together={('channel', 'zone')},
        ),
        migrations.AddIndex(
            model_name='channel',
            index=models.Index(fields=['status', 'is_online'], name='channels_status_9488f5_idx'),
        ),
        migrations.AddIndex(
            model_name='channel',
            index=models.Index(fields=['channel_type', 'category'], name='channels_channel_b7eea9_idx'),
        ),
        migrations.AddIndex(
            model_name='channel',
            index=models.Index(fields=['last_health_check'], name='channels_last_he_da88f4_idx'),
        ),
        migrations.AddIndex(
            model_name='epgprogram',
            index=models.Index(fields=['channel', 'start_time'], name='epg_channel_start_idx'),
        ),
        migrations.AddIndex(
            model_name='epgprogram',
            index=models.Index(fields=['start_time', 'end_time'], name='epg_time_range_idx'),
        ),
        migrations.AddIndex(
            model_name='epgprogram',
            index=models.Index(fields=['program_type'], name='epg_type_idx'),
        ),
        migrations.AddConstraint(
            model_name='epgprogram',
            constraint=models.CheckConstraint(condition=models.Q(('end_time__gt', models.F('start_time'))), name='epg_valid_time_range'),
        ),
        migrations.AddConstraint(
            model_name='epgprogram',
            constraint=models.CheckConstraint(condition=models.Q(('duration__gt', 0)), name='epg_positive_duration'),
        ),
        migrations.AddIndex(
            model_name='jingle',
            index=models.Index(fields=['channel', 'is_active'], name='jingles_channel_d7c7d8_idx'),
        ),
        migrations.AddIndex(
            model_name='jingle',
            index=models.Index(fields=['placement_type', 'is_active'], name='jingles_placeme_150487_idx'),
        ),
        migrations.AddIndex(
            model_name='jingle',
            index=models.Index(fields=['priority', 'is_active'], name='jingles_priorit_65aa69_idx'),
        ),
        migrations.AddIndex(
            model_name='jingledetection',
            index=models.Index(fields=['channel', 'detected_at'], name='jingle_dete_channel_18fbef_idx'),
        ),
        migrations.AddIndex(
            model_name='jingledetection',
            index=models.Index(fields=['jingle', 'detected_at'], name='jingle_dete_jingle__5ec887_idx'),
        ),
        migrations.AddIndex(
            model_name='jingledetection',
            index=models.Index(fields=['start_timestamp', 'end_timestamp'], name='jingle_dete_start_t_8492c4_idx'),
        ),
        migrations.AddIndex(
            model_name='jingledetection',
            index=models.Index(fields=['status', 'detected_at'], name='jingle_dete_status_a1756a_idx'),
        ),
        migrations.AddIndex(
            model_name='jingledetection',
            index=models.Index(fields=['confidence_score'], name='jingle_dete_confide_879f92_idx'),
        ),
    ]
