"""Импортирует IOC из текстового файла в таблицу dataset."""

from __future__ import annotations

import argparse
import asyncio
import logging
from pathlib import Path

from sqlalchemy.exc import SQLAlchemyError

from ioc_checker.database import Base, DatasetEntry, SessionLocal, engine
from ioc_checker.iocs import IOCType
from ioc_checker.iocs.text_parser import TextIOCParser


class DatasetImporter:
    """Загружает IOC в базу данных с нормализацией доменов."""

    def __init__(self) -> None:
        self._parser = TextIOCParser()
        self._logger = logging.getLogger(self.__class__.__name__)

    async def run(self, path: Path, label: str) -> None:
        """Импортирует IOC из ``path`` в таблицу с меткой ``label``."""

        if not path.exists():
            raise FileNotFoundError(path)
        cleaned_label = label.strip()
        if not cleaned_label:
            raise ValueError("Метка не может быть пустой")

        await self._ensure_schema()
        total = 0
        skipped = 0

        async with SessionLocal() as session:
            async with session.begin():
                with path.open("r", encoding="utf-8") as handle:
                    for line_number, raw_line in enumerate(handle, start=1):
                        candidate = raw_line.strip()
                        if not candidate:
                            self._logger.debug(
                                "Строка %d пуста, пропускаем", line_number
                            )
                            continue
                        indicator = self._extract_indicator(candidate, line_number)
                        if indicator is None:
                            skipped += 1
                            continue
                        entry = DatasetEntry(
                            ioc=indicator.value,
                            ioc_type=indicator.category,
                            label=cleaned_label,
                        )
                        session.add(entry)
                        total += 1
        self._logger.info(
            "Импорт завершён: добавлено %d записей, пропущено %d", total, skipped
        )

    async def _ensure_schema(self) -> None:
        """Убеждается, что таблица dataset существует."""

        self._logger.debug("Проверяем наличие таблицы dataset")
        async with engine.begin() as connection:
            await connection.run_sync(Base.metadata.create_all)

    def _extract_indicator(self, raw_value: str, line_number: int) -> IOCType | None:
        """Определяет тип IOC и приводит домен к punycode."""

        results = self._parser.parse(raw_value)
        if not results:
            self._logger.warning(
                "Строка %d не содержит поддерживаемых IOC: %s",
                line_number,
                raw_value,
            )
            return None
        if len(results) > 1:
            self._logger.warning(
                "Строка %d содержит несколько IOC, используется первый", line_number
            )
        indicator = results[0].indicator
        self._logger.debug(
            "Строка %d распознана как %s: %s",
            line_number,
            indicator.category,
            indicator.value,
        )
        return indicator


async def _main() -> None:
    """Точка входа для асинхронной части импорта."""

    parser = argparse.ArgumentParser(
        description="Импорт IOC из текстового файла в таблицу dataset",
    )
    parser.add_argument(
        "--source",
        type=Path,
        required=True,
        help="Путь до текстового файла с IOC",
    )
    parser.add_argument(
        "--label",
        type=str,
        required=True,
        help="Метка строки датасета",
    )
    args = parser.parse_args()

    importer = DatasetImporter()
    logger = logging.getLogger(__name__)
    try:
        await importer.run(args.source, args.label)
    except FileNotFoundError as exc:
        logger.error("Файл источника не найден: %s", exc)
        raise SystemExit(1) from exc
    except ValueError as exc:
        logger.error("Некорректные входные данные: %s", exc)
        raise SystemExit(1) from exc
    except SQLAlchemyError as exc:  # pragma: no cover - аварийная обработка
        logging.getLogger(__name__).exception("Ошибка базы данных: %s", exc)
        raise SystemExit(1) from exc


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(_main())
