import json
import sqlite3

from fluidattacks_core.semver.match_versions import match_vulnerable_versions

from labels.advisories.database import BaseDatabase
from labels.advisories.match_fixes import (
    match_fixes,
)
from labels.advisories.utils import create_advisory_from_record
from labels.model.advisories import Advisory, AdvisoryRecord


class RootsDatabase(BaseDatabase):
    def __init__(self) -> None:
        super().__init__(db_name="skims_sca_advisories.db")


DATABASE = RootsDatabase()


def fetch_advisory_from_database(
    cursor: sqlite3.Cursor,
    ecosystem: str,
    package_name: str,
) -> list[AdvisoryRecord]:
    cursor.execute(
        """
        SELECT
            adv_id,
            source,
            vulnerable_version,
            severity_level,
            severity_v4,
            epss,
            details,
            percentile,
            cwe_ids,
            cve_finding,
            auto_approve,
            fixed_versions,
            kev_catalog
        FROM advisories
        WHERE ecosystem = ? AND package_name = ?;
        """,
        (ecosystem, package_name),
    )
    records: list[AdvisoryRecord] = cursor.fetchall()
    return records


def fetch_safe_versions_from_database(
    cursor: sqlite3.Cursor,
    ecosystem: str,
    package_name: str,
) -> list[str]:
    cursor.execute(
        """
        SELECT safe_versions
        FROM safe_versions
        WHERE ecosystem = ? AND package_name = ?;
        """,
        (ecosystem, package_name),
    )
    row: tuple[str] | None = cursor.fetchone()
    if row and row[0]:
        result: list[str] = json.loads(row[0])
        return result
    return []


def get_package_advisories(
    ecosystem: str,
    package_name: str,
    version: str,
) -> list[Advisory]:
    connection = DATABASE.get_connection()
    cursor = connection.cursor()

    return [
        adv
        for advisory_record in fetch_advisory_from_database(cursor, ecosystem, package_name)
        if (adv := create_advisory_from_record(advisory_record, ecosystem, package_name, version))
    ]


def fetch_all_package_versions_from_database(
    cursor: sqlite3.Cursor,
    ecosystem: str,
    package_name: str,
) -> list[str]:
    cursor.execute(
        """
        SELECT available_versions
        FROM package_versions_registry
        WHERE ecosystem = ? AND package_name = ?;
        """,
        (ecosystem, package_name),
    )
    row: tuple[str] | None = cursor.fetchone()
    if row and row[0]:
        result: list[str] = json.loads(row[0])
        return result
    return []


def get_all_package_versions(
    ecosystem: str,
    package_name: str,
) -> list[str]:
    connection = DATABASE.get_connection()
    cursor = connection.cursor()
    return fetch_all_package_versions_from_database(cursor, ecosystem, package_name)


def get_safe_versions(
    ecosystem: str,
    package_name: str,
) -> list[str]:
    connection = DATABASE.get_connection()
    cursor = connection.cursor()
    return fetch_safe_versions_from_database(cursor, ecosystem, package_name)


def get_vulnerabilities(
    ecosystem: str, product: str, version: str, safe_versions: list[str] | None
) -> list[Advisory]:
    if (
        product
        and version
        and (advisories := get_package_advisories(ecosystem, product.lower(), version))
    ):
        all_package_versions = get_all_package_versions(ecosystem, product.lower())
        return [
            match_fixes(version.lower(), advisor, safe_versions, all_package_versions, advisories)
            for advisor in advisories
            if match_vulnerable_versions(version.lower(), advisor.vulnerable_version)
        ]
    return []
