#!/usr/bin/env python3
"""
souleyez.storage.exploits - Manage SearchSploit exploit data
"""

from typing import Any, Dict, List, Optional

from souleyez.storage.database import get_db


def add_exploit(
    engagement_id: int,
    edb_id: str,
    title: str,
    platform: str,
    exploit_type: str,
    url: str,
    date_published: str,
    search_term: str,
    service_id: Optional[int] = None,
) -> int:
    """Add a new exploit to the database."""
    db = get_db()
    conn = db.get_connection()

    cursor = conn.execute(
        """
        INSERT INTO exploits (
            engagement_id, service_id, edb_id, title, platform, 
            type, url, date_published, search_term
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    """,
        (
            engagement_id,
            service_id,
            edb_id,
            title,
            platform,
            exploit_type,
            url,
            date_published,
            search_term,
        ),
    )

    exploit_id = cursor.lastrowid
    conn.commit()
    conn.close()

    return exploit_id


def get_exploits_by_engagement(engagement_id: int) -> List[Dict[str, Any]]:
    """Get all exploits for an engagement."""
    db = get_db()
    conn = db.get_connection()

    results = conn.execute(
        """
        SELECT 
            e.*,
            s.port,
            s.service_name,
            s.service_version,
            h.ip_address
        FROM exploits e
        LEFT JOIN services s ON e.service_id = s.id
        LEFT JOIN hosts h ON s.host_id = h.id
        WHERE e.engagement_id = ?
        ORDER BY e.found_at DESC
    """,
        (engagement_id,),
    ).fetchall()

    conn.close()

    return [dict(r) for r in results]


def get_exploits_by_service(service_id: int) -> List[Dict[str, Any]]:
    """Get all exploits for a specific service."""
    db = get_db()
    conn = db.get_connection()

    results = conn.execute(
        """
        SELECT * FROM exploits
        WHERE service_id = ?
        ORDER BY found_at DESC
    """,
        (service_id,),
    ).fetchall()

    conn.close()

    return [dict(r) for r in results]


def get_exploit_stats(engagement_id: int) -> Dict[str, Any]:
    """Get exploit statistics for an engagement with detailed breakdowns."""
    db = get_db()
    conn = db.get_connection()

    # Get basic stats
    stats = conn.execute(
        """
        SELECT
            COUNT(*) as total,
            COUNT(DISTINCT platform) as platforms,
            COUNT(DISTINCT type) as types,
            COUNT(DISTINCT service_id) as services_with_exploits
        FROM exploits
        WHERE engagement_id = ?
    """,
        (engagement_id,),
    ).fetchone()

    result = (
        dict(stats)
        if stats
        else {"total": 0, "platforms": 0, "types": 0, "services_with_exploits": 0}
    )

    # Get platform breakdown (top 5)
    platform_breakdown = conn.execute(
        """
        SELECT platform, COUNT(*) as count
        FROM exploits
        WHERE engagement_id = ?
        GROUP BY platform
        ORDER BY count DESC
        LIMIT 5
    """,
        (engagement_id,),
    ).fetchall()
    result["platform_breakdown"] = [
        {"platform": row["platform"], "count": row["count"]}
        for row in platform_breakdown
    ]

    # Get type breakdown (top 5)
    type_breakdown = conn.execute(
        """
        SELECT type, COUNT(*) as count
        FROM exploits
        WHERE engagement_id = ?
        GROUP BY type
        ORDER BY count DESC
        LIMIT 5
    """,
        (engagement_id,),
    ).fetchall()
    result["type_breakdown"] = [
        {"type": row["type"], "count": row["count"]} for row in type_breakdown
    ]

    conn.close()

    return result


def delete_exploit(exploit_id: int) -> bool:
    """Delete a single exploit by ID."""
    db = get_db()
    conn = db.get_connection()

    cursor = conn.execute("DELETE FROM exploits WHERE id = ?", (exploit_id,))
    rows_deleted = cursor.rowcount

    conn.commit()
    conn.close()

    return rows_deleted > 0


def delete_exploits_by_engagement(engagement_id: int) -> int:
    """Delete all exploits for an engagement. Returns count of deleted exploits."""
    db = get_db()
    conn = db.get_connection()

    cursor = conn.execute(
        "DELETE FROM exploits WHERE engagement_id = ?", (engagement_id,)
    )
    rows_deleted = cursor.rowcount

    conn.commit()
    conn.close()

    return rows_deleted


def delete_exploits_by_ids(exploit_ids: List[int]) -> int:
    """Delete multiple exploits by their IDs. Returns count of deleted exploits."""
    if not exploit_ids:
        return 0

    db = get_db()
    conn = db.get_connection()

    placeholders = ",".join("?" * len(exploit_ids))
    query = f"DELETE FROM exploits WHERE id IN ({placeholders})"

    cursor = conn.execute(query, exploit_ids)
    rows_deleted = cursor.rowcount

    conn.commit()
    conn.close()

    return rows_deleted


def search_exploits(engagement_id: int, search_term: str) -> List[Dict[str, Any]]:
    """Search exploits by term using multi-keyword AND-based search."""
    db = get_db()
    conn = db.get_connection()

    # Split search term into keywords for AND-based search
    keywords = search_term.strip().split()

    # Build base query
    query = """
        SELECT
            e.*,
            s.port,
            s.service_name,
            h.ip_address
        FROM exploits e
        LEFT JOIN services s ON e.service_id = s.id
        LEFT JOIN hosts h ON s.host_id = h.id
        WHERE e.engagement_id = ?
    """

    # Start with engagement_id parameter
    params = [engagement_id]

    # Add AND condition for each keyword
    for keyword in keywords:
        query += """
        AND (
            e.title LIKE ?
            OR e.platform LIKE ?
            OR e.search_term LIKE ?
        )
        """
        # Add three parameters (one for each field) for this keyword
        keyword_pattern = f"%{keyword}%"
        params.extend([keyword_pattern, keyword_pattern, keyword_pattern])

    query += "ORDER BY e.found_at DESC"

    results = conn.execute(query, params).fetchall()

    conn.close()

    return [dict(r) for r in results]
