import logging
from collections import Counter
from django.utils.timezone import now

from .models import ScanProfile, ScanRun, ScanFinding
from .checks import router, dns, ingress, cameras, tls, ports
from .checks.base import Finding
from .notifications import notify_telegram

logger = logging.getLogger(__name__)

CHECK_MODULES = [router, dns, ingress, cameras, tls, ports]


def run_scan(profile_id: int, triggered_by: str = 'scheduler') -> int:
    """
    Run all checks for the given profile. Returns the ScanRun PK.
    Called by APScheduler jobs and TriggerScanView.
    """
    profile = ScanProfile.objects.get(pk=profile_id)
    run = ScanRun.objects.create(
        profile=profile,
        status='running',
        triggered_by=triggered_by,
    )
    logger.info(f'Starting netscan run #{run.pk} for profile "{profile.name}" (triggered_by={triggered_by})')

    all_findings: list[Finding] = []

    for mod in CHECK_MODULES:
        mod_name = mod.__name__.split('.')[-1]
        try:
            findings = mod.run(profile)
            all_findings.extend(findings)
            logger.debug(f'  {mod_name}: {len(findings)} findings')
        except Exception as e:
            logger.exception(f'  {mod_name}: uncaught exception')
            all_findings.append(Finding(
                check_name=mod_name,
                severity='warning',
                title=f'{mod_name}: check errored',
                detail=str(e),
                raw={'exception': str(e)},
            ))

    ScanFinding.objects.bulk_create([
        ScanFinding(
            run=run,
            check_name=f.check_name,
            severity=f.severity,
            title=f.title,
            detail=f.detail,
            raw=f.raw,
        )
        for f in all_findings
    ])

    summary = dict(Counter(f.severity for f in all_findings))
    run.summary = summary
    run.status = 'success'
    run.finished_at = now()
    run.save()

    profile.last_run_at = now()
    profile.save(update_fields=['last_run_at'])

    if profile.telegram_bot_token and profile.telegram_chat_id:
        try:
            notify_telegram(profile, run, all_findings)
        except Exception as e:
            logger.warning(f'Telegram notification failed: {e}')

    logger.info(f'Finished netscan run #{run.pk}: {summary}')
    return run.pk
