# Generated by Django 5.2.15 on 2026-06-16 09:53

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


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        ('operations', '0002_alter_historicalinternaltask_status_and_more'),
        ('technical', '0004_remove_wordpressplugin_uniq_wordpress_plugin_slug_per_site_and_more'),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='MonitorCheck',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('checked_at', models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Verificado em')),
                ('result', models.CharField(choices=[('up', 'Operacional'), ('degraded', 'Degradado'), ('down', 'Falhou'), ('maintenance', 'Manutenção'), ('skipped', 'Ignorado')], db_index=True, max_length=20, verbose_name='Resultado')),
                ('http_status', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Código HTTP')),
                ('response_time_ms', models.PositiveIntegerField(blank=True, null=True, verbose_name='Tempo de resposta (ms)')),
                ('final_url', models.URLField(blank=True, max_length=700, verbose_name='URL final')),
                ('redirect_count', models.PositiveSmallIntegerField(default=0, verbose_name='Redirecionamentos')),
                ('resolved_ip', models.GenericIPAddressField(blank=True, null=True, verbose_name='IP resolvido')),
                ('response_size_bytes', models.PositiveIntegerField(blank=True, null=True, verbose_name='Tamanho da resposta')),
                ('content_match', models.BooleanField(blank=True, null=True, verbose_name='Conteúdo validado')),
                ('ssl_valid', models.BooleanField(blank=True, null=True, verbose_name='SSL válido')),
                ('ssl_issuer', models.CharField(blank=True, max_length=250, verbose_name='Emissor SSL')),
                ('ssl_expires_at', models.DateTimeField(blank=True, null=True, verbose_name='SSL expira em')),
                ('ssl_days_remaining', models.IntegerField(blank=True, null=True, verbose_name='Dias de SSL')),
                ('error_type', models.CharField(blank=True, choices=[('', 'Sem erro'), ('timeout', 'Timeout'), ('dns', 'DNS'), ('connection', 'Ligação'), ('ssl', 'SSL'), ('http', 'Código HTTP'), ('content', 'Conteúdo'), ('security', 'Segurança'), ('other', 'Outro')], max_length=20, verbose_name='Tipo de erro')),
                ('error_message', models.TextField(blank=True, verbose_name='Erro')),
                ('details', models.JSONField(blank=True, default=dict, verbose_name='Detalhes técnicos')),
            ],
            options={
                'verbose_name': 'Verificação de website',
                'verbose_name_plural': 'Verificações de websites',
                'ordering': ['-checked_at'],
            },
        ),
        migrations.CreateModel(
            name='HistoricalWebsiteMonitor',
            fields=[
                ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
                ('public_id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)),
                ('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Criado em')),
                ('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Atualizado em')),
                ('name', models.CharField(max_length=180, verbose_name='Nome do monitor')),
                ('url', models.URLField(max_length=500, verbose_name='URL a verificar')),
                ('is_active', models.BooleanField(db_index=True, default=True, verbose_name='Monitorização ativa')),
                ('client_visible', models.BooleanField(default=True, verbose_name='Visível no portal do cliente')),
                ('http_method', models.CharField(choices=[('GET', 'GET'), ('HEAD', 'HEAD')], default='GET', max_length=8, verbose_name='Método HTTP')),
                ('interval_minutes', models.PositiveIntegerField(choices=[(1, 'A cada minuto'), (5, 'A cada 5 minutos'), (10, 'A cada 10 minutos'), (15, 'A cada 15 minutos'), (30, 'A cada 30 minutos'), (60, 'A cada hora'), (360, 'A cada 6 horas'), (1440, 'Diariamente')], default=5, verbose_name='Intervalo')),
                ('timeout_seconds', models.PositiveSmallIntegerField(default=15, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(60)], verbose_name='Timeout (segundos)')),
                ('expected_status_codes', models.CharField(default='200-399', help_text='Ex.: 200,204,301 ou 200-399.', max_length=100, verbose_name='Códigos HTTP esperados')),
                ('expected_text', models.CharField(blank=True, help_text='Opcional. A verificação falha se o texto não estiver no conteúdo recebido.', max_length=250, verbose_name='Texto obrigatório na resposta')),
                ('follow_redirects', models.BooleanField(default=True, verbose_name='Seguir redirecionamentos')),
                ('verify_ssl', models.BooleanField(default=True, verbose_name='Validar ligação SSL')),
                ('inspect_ssl_certificate', models.BooleanField(default=True, verbose_name='Analisar certificado SSL')),
                ('ssl_warning_days', models.PositiveSmallIntegerField(default=30, verbose_name='Avisar SSL a expirar (dias)')),
                ('warning_response_ms', models.PositiveIntegerField(default=2500, verbose_name='Avisar resposta lenta (ms)')),
                ('allow_private_networks', models.BooleanField(default=False, help_text='Ative apenas para monitorizar serviços internos autorizados.', verbose_name='Permitir rede privada')),
                ('alert_after_failures', models.PositiveSmallIntegerField(default=2, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(20)], verbose_name='Abrir incidente após falhas')),
                ('recover_after_successes', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(20)], verbose_name='Resolver após sucessos')),
                ('create_incident', models.BooleanField(default=True, verbose_name='Criar incidente automaticamente')),
                ('create_task', models.BooleanField(default=True, verbose_name='Criar tarefa interna')),
                ('notify_internal', models.BooleanField(default=True, verbose_name='Notificar equipa')),
                ('notify_client', models.BooleanField(default=False, verbose_name='Notificar cliente')),
                ('status', models.CharField(choices=[('pending', 'Por verificar'), ('up', 'Operacional'), ('degraded', 'Desempenho degradado'), ('down', 'Indisponível'), ('maintenance', 'Em manutenção'), ('paused', 'Pausado')], db_index=True, default='pending', max_length=20, verbose_name='Estado atual')),
                ('maintenance_until', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Manutenção até')),
                ('last_checked_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Última verificação')),
                ('next_check_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Próxima verificação')),
                ('last_success_at', models.DateTimeField(blank=True, null=True, verbose_name='Último sucesso')),
                ('last_failure_at', models.DateTimeField(blank=True, null=True, verbose_name='Última falha')),
                ('last_response_ms', models.PositiveIntegerField(blank=True, null=True, verbose_name='Último tempo (ms)')),
                ('last_http_status', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Último HTTP')),
                ('last_error', models.TextField(blank=True, verbose_name='Último erro')),
                ('consecutive_failures', models.PositiveSmallIntegerField(default=0, verbose_name='Falhas consecutivas')),
                ('consecutive_successes', models.PositiveSmallIntegerField(default=0, verbose_name='Sucessos consecutivos')),
                ('history_id', models.AutoField(primary_key=True, serialize=False)),
                ('history_date', models.DateTimeField(db_index=True)),
                ('history_change_reason', models.CharField(max_length=100, null=True)),
                ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
                ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
                ('technical_asset', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='technical.technicalasset', verbose_name='Ativo técnico')),
            ],
            options={
                'verbose_name': 'historical Monitor de website',
                'verbose_name_plural': 'historical Monitores de websites',
                'ordering': ('-history_date', '-history_id'),
                'get_latest_by': ('history_date', 'history_id'),
            },
            bases=(simple_history.models.HistoricalChanges, models.Model),
        ),
        migrations.CreateModel(
            name='WebsiteMonitor',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('public_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
                ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Criado em')),
                ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Atualizado em')),
                ('name', models.CharField(max_length=180, verbose_name='Nome do monitor')),
                ('url', models.URLField(max_length=500, verbose_name='URL a verificar')),
                ('is_active', models.BooleanField(db_index=True, default=True, verbose_name='Monitorização ativa')),
                ('client_visible', models.BooleanField(default=True, verbose_name='Visível no portal do cliente')),
                ('http_method', models.CharField(choices=[('GET', 'GET'), ('HEAD', 'HEAD')], default='GET', max_length=8, verbose_name='Método HTTP')),
                ('interval_minutes', models.PositiveIntegerField(choices=[(1, 'A cada minuto'), (5, 'A cada 5 minutos'), (10, 'A cada 10 minutos'), (15, 'A cada 15 minutos'), (30, 'A cada 30 minutos'), (60, 'A cada hora'), (360, 'A cada 6 horas'), (1440, 'Diariamente')], default=5, verbose_name='Intervalo')),
                ('timeout_seconds', models.PositiveSmallIntegerField(default=15, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(60)], verbose_name='Timeout (segundos)')),
                ('expected_status_codes', models.CharField(default='200-399', help_text='Ex.: 200,204,301 ou 200-399.', max_length=100, verbose_name='Códigos HTTP esperados')),
                ('expected_text', models.CharField(blank=True, help_text='Opcional. A verificação falha se o texto não estiver no conteúdo recebido.', max_length=250, verbose_name='Texto obrigatório na resposta')),
                ('follow_redirects', models.BooleanField(default=True, verbose_name='Seguir redirecionamentos')),
                ('verify_ssl', models.BooleanField(default=True, verbose_name='Validar ligação SSL')),
                ('inspect_ssl_certificate', models.BooleanField(default=True, verbose_name='Analisar certificado SSL')),
                ('ssl_warning_days', models.PositiveSmallIntegerField(default=30, verbose_name='Avisar SSL a expirar (dias)')),
                ('warning_response_ms', models.PositiveIntegerField(default=2500, verbose_name='Avisar resposta lenta (ms)')),
                ('allow_private_networks', models.BooleanField(default=False, help_text='Ative apenas para monitorizar serviços internos autorizados.', verbose_name='Permitir rede privada')),
                ('alert_after_failures', models.PositiveSmallIntegerField(default=2, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(20)], verbose_name='Abrir incidente após falhas')),
                ('recover_after_successes', models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(20)], verbose_name='Resolver após sucessos')),
                ('create_incident', models.BooleanField(default=True, verbose_name='Criar incidente automaticamente')),
                ('create_task', models.BooleanField(default=True, verbose_name='Criar tarefa interna')),
                ('notify_internal', models.BooleanField(default=True, verbose_name='Notificar equipa')),
                ('notify_client', models.BooleanField(default=False, verbose_name='Notificar cliente')),
                ('status', models.CharField(choices=[('pending', 'Por verificar'), ('up', 'Operacional'), ('degraded', 'Desempenho degradado'), ('down', 'Indisponível'), ('maintenance', 'Em manutenção'), ('paused', 'Pausado')], db_index=True, default='pending', max_length=20, verbose_name='Estado atual')),
                ('maintenance_until', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Manutenção até')),
                ('last_checked_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Última verificação')),
                ('next_check_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Próxima verificação')),
                ('last_success_at', models.DateTimeField(blank=True, null=True, verbose_name='Último sucesso')),
                ('last_failure_at', models.DateTimeField(blank=True, null=True, verbose_name='Última falha')),
                ('last_response_ms', models.PositiveIntegerField(blank=True, null=True, verbose_name='Último tempo (ms)')),
                ('last_http_status', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Último HTTP')),
                ('last_error', models.TextField(blank=True, verbose_name='Último erro')),
                ('consecutive_failures', models.PositiveSmallIntegerField(default=0, verbose_name='Falhas consecutivas')),
                ('consecutive_successes', models.PositiveSmallIntegerField(default=0, verbose_name='Sucessos consecutivos')),
                ('technical_asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='website_monitors', to='technical.technicalasset', verbose_name='Ativo técnico')),
            ],
            options={
                'verbose_name': 'Monitor de website',
                'verbose_name_plural': 'Monitores de websites',
                'ordering': ['technical_asset__service__client__name', 'name'],
            },
        ),
        migrations.CreateModel(
            name='MonitorIncident',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('public_id', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)),
                ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Criado em')),
                ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Atualizado em')),
                ('title', models.CharField(max_length=220, verbose_name='Título')),
                ('reason', models.TextField(verbose_name='Motivo')),
                ('severity', models.CharField(choices=[('warning', 'Aviso'), ('critical', 'Crítico')], db_index=True, default='critical', max_length=20, verbose_name='Gravidade')),
                ('status', models.CharField(choices=[('open', 'Aberto'), ('acknowledged', 'Reconhecido'), ('resolved', 'Resolvido'), ('ignored', 'Ignorado')], db_index=True, default='open', max_length=20, verbose_name='Estado')),
                ('opened_at', models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Aberto em')),
                ('acknowledged_at', models.DateTimeField(blank=True, null=True, verbose_name='Reconhecido em')),
                ('resolved_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Resolvido em')),
                ('failure_count', models.PositiveIntegerField(default=1, verbose_name='Falhas registadas')),
                ('client_visible', models.BooleanField(default=True, verbose_name='Visível no portal do cliente')),
                ('resolution_note', models.TextField(blank=True, verbose_name='Nota de resolução')),
                ('acknowledged_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='acknowledged_monitor_incidents', to=settings.AUTH_USER_MODEL, verbose_name='Reconhecido por')),
                ('first_check', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incidents_started', to='monitoring.monitorcheck', verbose_name='Primeira verificação')),
                ('internal_task', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='monitoring_incidents', to='operations.internaltask', verbose_name='Tarefa interna')),
                ('last_check', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incidents_updated', to='monitoring.monitorcheck', verbose_name='Última verificação')),
                ('resolved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resolved_monitor_incidents', to=settings.AUTH_USER_MODEL, verbose_name='Resolvido por')),
                ('monitor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incidents', to='monitoring.websitemonitor', verbose_name='Monitor')),
            ],
            options={
                'verbose_name': 'Incidente de monitorização',
                'verbose_name_plural': 'Incidentes de monitorização',
                'ordering': ['status', '-opened_at'],
            },
        ),
        migrations.AddField(
            model_name='monitorcheck',
            name='monitor',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='checks', to='monitoring.websitemonitor', verbose_name='Monitor'),
        ),
        migrations.CreateModel(
            name='HistoricalMonitorIncident',
            fields=[
                ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
                ('public_id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)),
                ('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Criado em')),
                ('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Atualizado em')),
                ('title', models.CharField(max_length=220, verbose_name='Título')),
                ('reason', models.TextField(verbose_name='Motivo')),
                ('severity', models.CharField(choices=[('warning', 'Aviso'), ('critical', 'Crítico')], db_index=True, default='critical', max_length=20, verbose_name='Gravidade')),
                ('status', models.CharField(choices=[('open', 'Aberto'), ('acknowledged', 'Reconhecido'), ('resolved', 'Resolvido'), ('ignored', 'Ignorado')], db_index=True, default='open', max_length=20, verbose_name='Estado')),
                ('opened_at', models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Aberto em')),
                ('acknowledged_at', models.DateTimeField(blank=True, null=True, verbose_name='Reconhecido em')),
                ('resolved_at', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Resolvido em')),
                ('failure_count', models.PositiveIntegerField(default=1, verbose_name='Falhas registadas')),
                ('client_visible', models.BooleanField(default=True, verbose_name='Visível no portal do cliente')),
                ('resolution_note', models.TextField(blank=True, verbose_name='Nota de resolução')),
                ('history_id', models.AutoField(primary_key=True, serialize=False)),
                ('history_date', models.DateTimeField(db_index=True)),
                ('history_change_reason', models.CharField(max_length=100, null=True)),
                ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
                ('acknowledged_by', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Reconhecido por')),
                ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
                ('internal_task', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='operations.internaltask', verbose_name='Tarefa interna')),
                ('resolved_by', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Resolvido por')),
                ('first_check', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='monitoring.monitorcheck', verbose_name='Primeira verificação')),
                ('last_check', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='monitoring.monitorcheck', verbose_name='Última verificação')),
                ('monitor', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='monitoring.websitemonitor', verbose_name='Monitor')),
            ],
            options={
                'verbose_name': 'historical Incidente de monitorização',
                'verbose_name_plural': 'historical Incidentes de monitorização',
                'ordering': ('-history_date', '-history_id'),
                'get_latest_by': ('history_date', 'history_id'),
            },
            bases=(simple_history.models.HistoricalChanges, models.Model),
        ),
        migrations.AddIndex(
            model_name='websitemonitor',
            index=models.Index(fields=['is_active', 'next_check_at'], name='monitoring__is_acti_64719a_idx'),
        ),
        migrations.AddIndex(
            model_name='websitemonitor',
            index=models.Index(fields=['status', 'last_checked_at'], name='monitoring__status_0aff16_idx'),
        ),
        migrations.AddConstraint(
            model_name='websitemonitor',
            constraint=models.UniqueConstraint(fields=('technical_asset', 'url'), name='uniq_monitor_url_per_asset'),
        ),
        migrations.AddIndex(
            model_name='monitorincident',
            index=models.Index(fields=['status', 'severity', '-opened_at'], name='monitoring__status_29bcee_idx'),
        ),
        migrations.AddConstraint(
            model_name='monitorincident',
            constraint=models.UniqueConstraint(condition=models.Q(('status__in', ['open', 'acknowledged'])), fields=('monitor',), name='uniq_open_monitor_incident'),
        ),
        migrations.AddIndex(
            model_name='monitorcheck',
            index=models.Index(fields=['monitor', '-checked_at'], name='monitoring__monitor_45d319_idx'),
        ),
        migrations.AddIndex(
            model_name='monitorcheck',
            index=models.Index(fields=['result', '-checked_at'], name='monitoring__result_4f8e76_idx'),
        ),
    ]
