# src/core/database/db.py
import sqlite3
from contextlib import contextmanager
from pathlib import Path
from typing import Optional

from src.utils.logger import get_logger

logger = get_logger("database")


class Database:
    def __init__(
        self, db_path: str = "/home/lodqa/attack_module_data/security_scanner.db"
    ):
        self.db_path = Path(db_path)
        self.db_path.parent.mkdir(parents=True, exist_ok=True)
        self.conn: Optional[sqlite3.Connection]
        self.init_db()

    def connect(self):
        """Подключение к базе данных."""
        try:
            self.conn = sqlite3.connect(self.db_path, check_same_thread=False)
            self.conn.row_factory = sqlite3.Row
            logger.info(f"Connected to database at {self.db_path}")
        except sqlite3.Error as e:
            logger.error(f"Failed to connect to database: {e}")
            raise

    def init_db(self):
        """Инициализация базы данных и создание таблиц."""
        self.connect()
        cursor = self.conn.cursor()

        # Создание таблиц
        cursor.executescript("""
            CREATE TABLE IF NOT EXISTS sessions (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            );

            CREATE TABLE IF NOT EXISTS scans (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                session_id INTEGER,
                tool TEXT,
                args TEXT,
                summary TEXT,
                duration INTEGER,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS hosts (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                scan_id INTEGER,
                ip TEXT,
                mac TEXT,
                os TEXT,
                FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS ports (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                host_id INTEGER,
                protocol TEXT,
                port_num INTEGER,
                state TEXT,
                FOREIGN KEY (host_id) REFERENCES hosts(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS service (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                port_id INTEGER,
                name TEXT,
                product TEXT,
                extrainfo TEXT,
                ostype TEXT,
                FOREIGN KEY (port_id) REFERENCES ports(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS cpe (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                service_id INTEGER,
                name TEXT,
                FOREIGN KEY (service_id) REFERENCES service(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS modbus_scan_result (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                scan_id INTEGER,
                active_coils TEXT,
                active_discrete_inputs TEXT,
                active_holding_registers TEXT,
                active_input_registers TEXT,
                FOREIGN KEY (scan_id) REFERENCES scans(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS attacks (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                session_id INTEGER,
                tool TEXT,
                args TEXT,
                summary TEXT,
                duration INTEGER,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
            );

            CREATE TABLE IF NOT EXISTS attack_result (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                attack_id INTEGER,
                summary TEXT,
                FOREIGN KEY (attack_id) REFERENCES attacks(id) ON DELETE CASCADE
            );
        """)
        self.conn.commit()
        logger.info("Database tables initialized")

    @contextmanager
    def get_cursor(self):
        """Контекстный менеджер для работы с курсором."""
        cursor = self.conn.cursor()
        try:
            yield cursor
            self.conn.commit()
        except Exception as e:
            self.conn.rollback()
            logger.error(f"Database operation failed: {e}")
            raise
        finally:
            cursor.close()

    def close(self):
        """Закрытие соединения с базой данных."""
        if self.conn:
            self.conn.close()
            logger.info("Database connection closed")

