"""Vulnerability Snapshots Service - 业务逻辑层"""

import logging
from typing import List, Iterator

from apps.asset.repositories.snapshot import DjangoVulnerabilitySnapshotRepository
from apps.asset.services.asset.vulnerability_service import VulnerabilityService
from apps.asset.dtos.snapshot import VulnerabilitySnapshotDTO

logger = logging.getLogger(__name__)


class VulnerabilitySnapshotsService:
    """漏洞快照服务 - 统一管理快照和资产同步。

    流程与 Website/Directory 等保持一致：
    1. 保存到 VulnerabilitySnapshot 快照表（包含 scan_id）
    2. 转为 VulnerabilityDTO 并同步到 Vulnerability 资产表（基于 target_id）
    """

    def __init__(self):
        self.snapshot_repo = DjangoVulnerabilitySnapshotRepository()
        self.asset_service = VulnerabilityService()

    def save_and_sync(self, items: List[VulnerabilitySnapshotDTO]) -> None:
        """保存漏洞快照并同步到漏洞资产表。"""
        if not items:
            return
        
        # 检查 Scan 是否仍存在（防止删除后竞态写入）
        scan_id = items[0].scan_id
        from apps.scan.repositories import DjangoScanRepository
        if not DjangoScanRepository().exists(scan_id):
            logger.warning("Scan 已删除，跳过漏洞快照保存 - scan_id=%s, 数量=%d", scan_id, len(items))
            return
        
        try:
            logger.debug("保存漏洞快照并同步到资产表 - 数量: %d", len(items))

            # 步骤 1: 保存到快照表
            logger.debug("步骤 1: 保存到漏洞快照表")
            self.snapshot_repo.save_snapshots(items)

            # 步骤 2: 转换为资产 DTO 并保存到资产表
            logger.debug("步骤 2: 同步到漏洞资产表")
            asset_items = [item.to_asset_dto() for item in items]
            self.asset_service.bulk_create_ignore_conflicts(asset_items)

            logger.info("漏洞快照和资产数据保存成功 - 数量: %d", len(items))
            
            # 步骤 3: 发布漏洞保存信号（通知等模块可监听）
            from apps.common.signals import vulnerabilities_saved
            vulnerabilities_saved.send(
                sender=self.__class__,
                items=items,
                scan_id=scan_id,
                target_id=items[0].target_id if items else None
            )

        except Exception as e:
            logger.error(
                "保存漏洞快照失败 - 数量: %d, 错误: %s",
                len(items),
                str(e),
                exc_info=True,
            )
            raise

    # 智能过滤字段映射
    FILTER_FIELD_MAPPING = {
        'type': 'vuln_type',
        'url': 'url',
        'severity': 'severity',
        'source': 'source',
    }

    def get_by_scan(self, scan_id: int, filter_query: str = None):
        """按扫描任务获取所有漏洞快照。"""
        from apps.common.utils.filter_utils import apply_filters
        
        queryset = self.snapshot_repo.get_by_scan(scan_id)
        if filter_query:
            queryset = apply_filters(queryset, filter_query, self.FILTER_FIELD_MAPPING)
        return queryset

    def get_all(self, filter_query: str = None):
        """获取所有漏洞快照"""
        from apps.common.utils.filter_utils import apply_filters
        
        queryset = self.snapshot_repo.get_all()
        if filter_query:
            queryset = apply_filters(queryset, filter_query, self.FILTER_FIELD_MAPPING)
        return queryset

    def iter_vuln_urls_by_scan(self, scan_id: int, chunk_size: int = 1000) -> Iterator[str]:
        """流式获取某次扫描下的所有漏洞 URL。"""
        queryset = self.snapshot_repo.get_by_scan(scan_id)
        for snapshot in queryset.iterator(chunk_size=chunk_size):
            yield snapshot.url
