from __future__ import annotations

import json
import os

import pytest
from vunnel import result, workspace
from vunnel.providers.echo import Config, Provider
from vunnel.providers.echo.parser import Parser


class TestParser:
    @pytest.fixture()
    def mock_raw_data(self, helpers):
        """
        Returns stringified version of the following json

        ---
        """
        data = {
            "nginx": {
                "CVE-2021-3618": { "fixed_version": "1.21.0" },
                "CVE-2023-44487": { "fixed_version": "1.25.2" }
            },
            "python": {
                "CVE-2007-4559": { "fixed_version": "3.6.16" },
                "CVE-2009-2940": {},
                "CVE-2009-3720": {},
                "CVE-2013-0340": { "fixed_version": "3.6.15" },
                "CVE-2015-20107": { "fixed_version": "3.7.15" },
                "CVE-2016-3189": { "fixed_version": "3.7.13" },
                "CVE-2018-25032": { "fixed_version": "3.7.14" },
                "CVE-2019-12900": { "fixed_version": "3.7.13" },
                "CVE-2020-10735": { "fixed_version": "3.7.14" },
                "CVE-2020-29396": {},
                "CVE-2021-28861": { "fixed_version": "3.7.14" },
                "CVE-2021-32052": {},
                "CVE-2022-26488": { "fixed_version": "3.7.12" },
                "CVE-2022-37454": { "fixed_version": "3.7.16" },
                "CVE-2022-42919": { "fixed_version": "3.7.15" },
                "CVE-2022-45061": { "fixed_version": "3.7.15" },
                "CVE-2023-24329": { "fixed_version": "3.7.17" },
                "CVE-2023-27043": { "fixed_version": "2.7.18" },
                "CVE-2023-36632": { "fixed_version": "3.11.4" },
                "CVE-2023-40217": { "fixed_version": "3.8.18" },
                "CVE-2024-6232": { "fixed_version": "3.8.20" },
                "CVE-2024-7592": { "fixed_version": "3.8.20" },
                "CVE-2024-9287": { "fixed_version": "3.9.21" }
            },
        }


        return json.dumps(data)

    @pytest.fixture()
    def mock_parsed_data(self):
        """
        Returns the parsed output generated by AlpineDataProvider._load() for the mock_raw_data

        :return:
        """
        release = "rolling"
        data = {
            "nginx": {
                "CVE-2021-3618": { "fixed_version": "1.21.0" },
                "CVE-2023-44487": { "fixed_version": "1.25.2" }
            },
            "python": {
                "CVE-2007-4559": { "fixed_version": "3.6.16" },
                "CVE-2009-2940": {},
                "CVE-2009-3720": {},
                "CVE-2013-0340": { "fixed_version": "3.6.15" },
                "CVE-2015-20107": { "fixed_version": "3.7.15" },
                "CVE-2016-3189": { "fixed_version": "3.7.13" },
                "CVE-2018-25032": { "fixed_version": "3.7.14" },
                "CVE-2019-12900": { "fixed_version": "3.7.13" },
                "CVE-2020-10735": { "fixed_version": "3.7.14" },
                "CVE-2020-29396": {},
                "CVE-2021-28861": { "fixed_version": "3.7.14" },
                "CVE-2021-32052": {},
                "CVE-2022-26488": { "fixed_version": "3.7.12" },
                "CVE-2022-37454": { "fixed_version": "3.7.16" },
                "CVE-2022-42919": { "fixed_version": "3.7.15" },
                "CVE-2022-45061": { "fixed_version": "3.7.15" },
                "CVE-2023-24329": { "fixed_version": "3.7.17" },
                "CVE-2023-27043": { "fixed_version": "2.7.18" },
                "CVE-2023-36632": { "fixed_version": "3.11.4" },
                "CVE-2023-40217": { "fixed_version": "3.8.18" },
                "CVE-2024-6232": { "fixed_version": "3.8.20" },
                "CVE-2024-7592": { "fixed_version": "3.8.20" },
                "CVE-2024-9287": { "fixed_version": "3.9.21" }
            },
        }
        return release, data

    def test_normalize(self, mock_parsed_data, tmpdir):
        p = Parser(
            workspace=workspace.Workspace(tmpdir, "test", create=True),
            url="https://advisory.echohq.com/data.json",
            namespace="echo",
        )
        release = mock_parsed_data[0]
        data = mock_parsed_data[1]

        vuln_records = p._normalize(release, data)
        assert len(vuln_records) > 0
        assert all("Vulnerability" in x for x in vuln_records.values())
        assert sorted(vuln_records.keys()) == sorted(
            [
                "CVE-2007-4559",
                "CVE-2009-2940",
                "CVE-2009-3720",
                "CVE-2013-0340",
                "CVE-2015-20107",
                "CVE-2016-3189",
                "CVE-2018-25032",
                "CVE-2019-12900",
                "CVE-2020-10735",
                "CVE-2020-29396",
                "CVE-2021-28861",
                "CVE-2021-32052",
                "CVE-2021-3618",
                "CVE-2022-26488",
                "CVE-2022-37454",
                "CVE-2022-42919",
                "CVE-2022-45061",
                "CVE-2023-24329",
                "CVE-2023-27043",
                "CVE-2023-36632",
                "CVE-2023-40217",
                "CVE-2023-44487",
                "CVE-2024-6232",
                "CVE-2024-7592",
                "CVE-2024-9287",
            ],
        )


def test_provider_schema(helpers, disable_get_requests, monkeypatch):
    workspace = helpers.provider_workspace_helper(
        name=Provider.name(),
        input_fixture="test-fixtures/input",
    )
    c = Config()
    c.runtime.result_store = result.StoreStrategy.FLAT_FILE
    p = Provider(root=workspace.root, config=c)
    def mock_download():
        return None

    monkeypatch.setattr(p.parser, "_download", mock_download)

    p.update(None)

    assert workspace.num_result_entries() == 25
    assert workspace.result_schemas_valid(require_entries=True)


def test_provider_via_snapshot(helpers, disable_get_requests, monkeypatch):
    workspace = helpers.provider_workspace_helper(
        name=Provider.name(),
        input_fixture="test-fixtures/input",
    )

    c = Config()
    # keep all of the default values for the result store, but override the strategy
    c.runtime.result_store = result.StoreStrategy.FLAT_FILE
    p = Provider(
        root=workspace.root,
        config=c,
    )

    def mock_download():
        return None

    monkeypatch.setattr(p.parser, "_download", mock_download)

    p.update(None)

    workspace.assert_result_snapshots()
