# Generated by Django 5.2.10 on 2026-02-27 06:15

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


class Migration(migrations.Migration):

    dependencies = [
        ("policy", "0006_alter_policylevelkeywordmodel_level_and_more"),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name="GateActionAuditLog",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
                    ),
                ),
                (
                    "action",
                    models.CharField(
                        choices=[
                            ("approve", "审核通过"),
                            ("reject", "审核拒绝"),
                            ("rollback", "回滚生效"),
                            ("override", "临时豁免"),
                            ("auto_approve", "自动生效"),
                            ("level_change", "档位变更"),
                        ],
                        max_length=20,
                        verbose_name="操作类型",
                    ),
                ),
                (
                    "before_state",
                    models.JSONField(
                        blank=True,
                        default=dict,
                        help_text="操作前的关键字段快照",
                        verbose_name="操作前状态",
                    ),
                ),
                (
                    "after_state",
                    models.JSONField(
                        blank=True,
                        default=dict,
                        help_text="操作后的关键字段快照",
                        verbose_name="操作后状态",
                    ),
                ),
                (
                    "reason",
                    models.TextField(
                        blank=True, help_text="拒绝/回滚/豁免时填写的原因", verbose_name="操作原因"
                    ),
                ),
                (
                    "rule_version",
                    models.CharField(
                        blank=True,
                        help_text="执行时的规则版本号",
                        max_length=50,
                        verbose_name="规则版本",
                    ),
                ),
                ("created_at", models.DateTimeField(auto_now_add=True, verbose_name="创建时间")),
            ],
            options={
                "verbose_name": "闸门操作审计日志",
                "verbose_name_plural": "闸门操作审计日志",
                "db_table": "gate_action_audit_log",
                "ordering": ["-created_at"],
            },
        ),
        migrations.CreateModel(
            name="PolicyIngestionConfig",
            fields=[
                (
                    "singleton_id",
                    models.AutoField(primary_key=True, serialize=False, verbose_name="单例ID"),
                ),
                (
                    "auto_approve_enabled",
                    models.BooleanField(
                        default=False,
                        help_text="是否启用高置信度事件自动生效",
                        verbose_name="启用自动生效",
                    ),
                ),
                (
                    "auto_approve_min_level",
                    models.CharField(
                        choices=[
                            ("P0", "P0 - 常态"),
                            ("P1", "P1 - 预警"),
                            ("P2", "P2 - 干预"),
                            ("P3", "P3 - 危机"),
                        ],
                        default="P2",
                        help_text="P2 表示 P2/P3 可自动生效，P0 表示所有档位",
                        max_length=2,
                        verbose_name="自动生效最低档位",
                    ),
                ),
                (
                    "auto_approve_threshold",
                    models.FloatField(
                        default=0.85,
                        help_text="AI 置信度达到此阈值才可自动生效（0.0-1.0）",
                        verbose_name="自动生效置信度阈值",
                    ),
                ),
                (
                    "p23_sla_hours",
                    models.IntegerField(
                        default=2,
                        help_text="P2/P3 事件审核超时时间",
                        verbose_name="P2/P3 SLA（小时）",
                    ),
                ),
                (
                    "normal_sla_hours",
                    models.IntegerField(
                        default=24,
                        help_text="P0/P1 事件审核超时时间",
                        verbose_name="普通 SLA（小时）",
                    ),
                ),
                ("version", models.IntegerField(default=1, verbose_name="配置版本")),
                ("updated_at", models.DateTimeField(auto_now=True, verbose_name="更新时间")),
                ("created_at", models.DateTimeField(auto_now_add=True, verbose_name="创建时间")),
            ],
            options={
                "verbose_name": "政策摄入配置",
                "verbose_name_plural": "政策摄入配置",
                "db_table": "policy_ingestion_config",
            },
        ),
        migrations.CreateModel(
            name="SentimentGateConfig",
            fields=[
                (
                    "id",
                    models.BigAutoField(
                        auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
                    ),
                ),
                (
                    "asset_class",
                    models.CharField(
                        choices=[
                            ("equity", "股票"),
                            ("bond", "债券"),
                            ("commodity", "商品"),
                            ("fx", "外汇"),
                            ("crypto", "加密货币"),
                            ("all", "全资产"),
                        ],
                        max_length=20,
                        unique=True,
                        verbose_name="资产分类",
                    ),
                ),
                (
                    "heat_l1_threshold",
                    models.FloatField(
                        default=30.0,
                        help_text="热度达到此值触发 L1 关注",
                        verbose_name="热度 L1 阈值",
                    ),
                ),
                (
                    "heat_l2_threshold",
                    models.FloatField(
                        default=60.0,
                        help_text="热度达到此值触发 L2 警戒",
                        verbose_name="热度 L2 阈值",
                    ),
                ),
                (
                    "heat_l3_threshold",
                    models.FloatField(
                        default=85.0,
                        help_text="热度达到此值触发 L3 严控",
                        verbose_name="热度 L3 阈值",
                    ),
                ),
                (
                    "sentiment_l1_threshold",
                    models.FloatField(
                        default=-0.3,
                        help_text="情绪低于此值触发 L1 关注（如 -0.3）",
                        verbose_name="情绪 L1 阈值",
                    ),
                ),
                (
                    "sentiment_l2_threshold",
                    models.FloatField(
                        default=-0.6,
                        help_text="情绪低于此值触发 L2 警戒",
                        verbose_name="情绪 L2 阈值",
                    ),
                ),
                (
                    "sentiment_l3_threshold",
                    models.FloatField(
                        default=-0.8,
                        help_text="情绪低于此值触发 L3 严控",
                        verbose_name="情绪 L3 阈值",
                    ),
                ),
                (
                    "max_position_cap_l2",
                    models.FloatField(
                        default=0.7,
                        help_text="L2 警戒时最大仓位比例（0.7 表示 70%）",
                        verbose_name="L2 最大仓位上限",
                    ),
                ),
                (
                    "max_position_cap_l3",
                    models.FloatField(
                        default=0.3,
                        help_text="L3 严控时最大仓位比例（0.3 表示 30%）",
                        verbose_name="L3 最大仓位上限",
                    ),
                ),
                ("enabled", models.BooleanField(default=True, verbose_name="启用")),
                ("version", models.IntegerField(default=1, verbose_name="配置版本")),
                ("updated_at", models.DateTimeField(auto_now=True, verbose_name="更新时间")),
                ("created_at", models.DateTimeField(auto_now_add=True, verbose_name="创建时间")),
            ],
            options={
                "verbose_name": "热点情绪闸门配置",
                "verbose_name_plural": "热点情绪闸门配置",
                "db_table": "sentiment_gate_config",
                "ordering": ["asset_class"],
            },
        ),
        migrations.AddField(
            model_name="policylog",
            name="asset_class",
            field=models.CharField(
                blank=True,
                choices=[
                    ("equity", "股票"),
                    ("bond", "债券"),
                    ("commodity", "商品"),
                    ("fx", "外汇"),
                    ("crypto", "加密货币"),
                    ("all", "全资产"),
                ],
                db_index=True,
                help_text="按资产类约束",
                max_length=20,
                null=True,
                verbose_name="资产分类",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="asset_scope",
            field=models.JSONField(
                blank=True,
                default=list,
                help_text="JSON数组，如 ['ASSET_CODE_1', 'ASSET_CODE_2']",
                verbose_name="受影响资产范围",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="effective_at",
            field=models.DateTimeField(blank=True, null=True, verbose_name="生效时间"),
        ),
        migrations.AddField(
            model_name="policylog",
            name="effective_by",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                related_name="effected_policies",
                to=settings.AUTH_USER_MODEL,
                verbose_name="生效操作人",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="event_type",
            field=models.CharField(
                choices=[
                    ("policy", "政策事件"),
                    ("hotspot", "热点事件"),
                    ("sentiment", "情绪事件"),
                    ("mixed", "混合事件"),
                ],
                db_index=True,
                default="policy",
                help_text="区分政策事件与热点情绪事件",
                max_length=20,
                verbose_name="事件类型",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="gate_effective",
            field=models.BooleanField(
                db_index=True,
                default=False,
                help_text="是否已审核通过并生效",
                verbose_name="闸门已生效",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="gate_level",
            field=models.CharField(
                blank=True,
                choices=[
                    ("L0", "L0 - 正常"),
                    ("L1", "L1 - 关注"),
                    ("L2", "L2 - 警戒"),
                    ("L3", "L3 - 严控"),
                ],
                db_index=True,
                help_text="热点情绪闸门等级 L0-L3",
                max_length=2,
                null=True,
                verbose_name="闸门等级",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="heat_score",
            field=models.FloatField(
                blank=True,
                help_text="0-100，数值越高热度越高",
                null=True,
                validators=[
                    django.core.validators.MinValueValidator(0),
                    django.core.validators.MaxValueValidator(100),
                ],
                verbose_name="热度评分",
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="rollback_reason",
            field=models.TextField(
                blank=True, help_text="回滚生效时填写的原因", verbose_name="回滚原因"
            ),
        ),
        migrations.AddField(
            model_name="policylog",
            name="sentiment_score",
            field=models.FloatField(
                blank=True,
                help_text="-1.0 ~ +1.0，负值悲观，正值乐观",
                null=True,
                validators=[
                    django.core.validators.MinValueValidator(-1.0),
                    django.core.validators.MaxValueValidator(1.0),
                ],
                verbose_name="情绪评分",
            ),
        ),
        migrations.AddIndex(
            model_name="policylog",
            index=models.Index(
                fields=["event_type", "-event_date"], name="policy_log_event_t_3451e6_idx"
            ),
        ),
        migrations.AddIndex(
            model_name="policylog",
            index=models.Index(
                fields=["gate_effective", "event_type"], name="policy_log_gate_ef_b0d188_idx"
            ),
        ),
        migrations.AddIndex(
            model_name="policylog",
            index=models.Index(
                fields=["asset_class", "gate_level"], name="policy_log_asset_c_aa2d0a_idx"
            ),
        ),
        migrations.AddField(
            model_name="gateactionauditlog",
            name="event",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="audit_logs",
                to="policy.policylog",
                verbose_name="关联事件",
            ),
        ),
        migrations.AddField(
            model_name="gateactionauditlog",
            name="operator",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to=settings.AUTH_USER_MODEL,
                verbose_name="操作人",
            ),
        ),
        migrations.AddField(
            model_name="policyingestionconfig",
            name="updated_by",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to=settings.AUTH_USER_MODEL,
                verbose_name="更新人",
            ),
        ),
        migrations.AddField(
            model_name="sentimentgateconfig",
            name="updated_by",
            field=models.ForeignKey(
                blank=True,
                null=True,
                on_delete=django.db.models.deletion.SET_NULL,
                to=settings.AUTH_USER_MODEL,
                verbose_name="更新人",
            ),
        ),
        migrations.AddIndex(
            model_name="gateactionauditlog",
            index=models.Index(
                fields=["event", "-created_at"], name="gate_action_event_i_a1dbb8_idx"
            ),
        ),
        migrations.AddIndex(
            model_name="gateactionauditlog",
            index=models.Index(fields=["action"], name="gate_action_action_0e5c68_idx"),
        ),
        migrations.AddIndex(
            model_name="gateactionauditlog",
            index=models.Index(fields=["operator"], name="gate_action_operato_b491c5_idx"),
        ),
        # 数据回填：确保存量数据与新口径一致
        migrations.RunPython(
            code=lambda apps, schema_editor: _backfill_policy_log_data(apps),
            reverse_code=migrations.RunPython.noop,
        ),
    ]


def _backfill_policy_log_data(apps):
    """
    回填 PolicyLog 存量数据

    1. 回填 event_type = 'policy'（所有政策事件）
    2. 回填 gate_effective = True（已审核通过的事件）
    3. 回填 effective_at（已审核通过的事件使用 reviewed_at）
    """
    from django.utils import timezone

    PolicyLog = apps.get_model("policy", "PolicyLog")

    # 统计更新数量
    event_type_updated = 0
    gate_effective_updated = 0

    # 1. 回填 event_type（所有现有记录默认为政策事件）
    policies_without_type = PolicyLog.objects.filter(event_type__isnull=True)
    event_type_updated = policies_without_type.count()
    if event_type_updated > 0:
        policies_without_type.update(event_type="policy")

    # 2. 回填 gate_effective 和 effective_at
    # 已审核通过的状态包括：manual_approved, auto_approved
    approved_statuses = ["manual_approved", "auto_approved"]
    approved_policies = PolicyLog.objects.filter(
        audit_status__in=approved_statuses,
        gate_effective=False,
    )

    for policy in approved_policies:
        policy.gate_effective = True
        # 使用 reviewed_at 作为 effective_at，如果没有则使用 created_at
        if policy.reviewed_at:
            policy.effective_at = policy.reviewed_at
        else:
            policy.effective_at = policy.created_at or timezone.now()
        policy.save(update_fields=["gate_effective", "effective_at"])
        gate_effective_updated += 1

    # 输出日志
    print(
        f"[Migration 0007] Data backfill completed: "
        f"event_type={event_type_updated}, gate_effective={gate_effective_updated}"
    )

