import os.path

import pytest

from debputy.filesystem_scan import DebputyFSIsROError
from debputy.plugin.api import (
    DebputyPluginInitializer,
    BinaryCtrlAccessor,
    MetadataDetectorPackageContext,
    VirtualPath,
)
from debputy.plugin.api.impl_types import PluginConflictError, PluginAPIViolationError
from debputy.plugin.api.test_api import (
    initialize_plugin_under_test_preloaded,
    virtual_path,
    build_virtual_file_system,
    package_metadata_context,
    initialize_plugin_under_test_from_desc,
)

CUSTOM_PLUGIN_JSON_FILE = os.path.join(
    os.path.dirname(__file__), "data", "custom-plugin.json.in"
)


def bad_metadata_detector_fs_rw(
    path: VirtualPath,
    _ctrl: BinaryCtrlAccessor,
    _context: MetadataDetectorPackageContext,
) -> None:
    del path["foo"]


def conflicting_plugin(api: DebputyPluginInitializer) -> None:
    api.packager_provided_file(
        "logrotate",
        "/some/where/that/is/not/etc/logrotate.d/{name}",
    )


def bad_plugin(api: DebputyPluginInitializer) -> None:
    api.metadata_or_maintscript_detector("fs_rw", bad_metadata_detector_fs_rw)


def test_conflict_with_debputy():
    with pytest.raises(PluginConflictError) as e_info:
        initialize_plugin_under_test_preloaded(
            1,
            conflicting_plugin,
            plugin_name="conflicting-plugin",
        )
    message = (
        'The stem "logrotate" is registered twice for packager provided files.'
        " Once by debputy and once by conflicting-plugin"
    )
    assert message == e_info.value.args[0]


def test_metadata_read_only():
    plugin = initialize_plugin_under_test_preloaded(
        1,
        bad_plugin,
        plugin_name="bad-plugin",
    )
    fs = build_virtual_file_system(["./foo"])
    with pytest.raises(PluginAPIViolationError) as e_info:
        plugin.run_metadata_detector("fs_rw", fs)

    assert isinstance(e_info.value.__cause__, DebputyFSIsROError)


def test_packager_provided_files():
    plugin = initialize_plugin_under_test_from_desc(CUSTOM_PLUGIN_JSON_FILE)
    assert plugin.packager_provided_files_by_stem().keys() == {
        "my-file",
        "test-file-from-json",
    }
    my_file = [p for p in plugin.packager_provided_files() if p.stem == "my-file"][0]

    assert my_file.stem == "my-file"
    assert my_file.compute_dest("g++-3.1")[1] == "g__-3.1.conf"


def test_path_checks():
    symlink_path = "./foo"
    with pytest.raises(ValueError) as e_info:
        virtual_path(symlink_path, link_target="/bar", mode=0o0755)
    assert (
        e_info.value.args[0]
        == f'Please do not provide mode for symlinks. Triggered by "{symlink_path}"'
    )
    with pytest.raises(ValueError) as e_info:
        virtual_path(symlink_path + "/", link_target="/bar")
    msg = (
        "Path name looks like a directory, but a symlink target was also provided."
        f' Please remove the trailing slash OR the symlink_target. Triggered by "{symlink_path}/"'
    )
    assert e_info.value.args[0] == msg


def test_metadata_detector_applies_to_check():
    plugin_name = "custom-plugin"
    metadata_detector_id = "udeb-only"
    plugin = initialize_plugin_under_test_from_desc(CUSTOM_PLUGIN_JSON_FILE)
    with pytest.raises(ValueError) as e_info:
        plugin.run_metadata_detector(
            metadata_detector_id,
            build_virtual_file_system(["./usr/share/doc/foo/copyright"]),
        )
    msg = f'The detector "{metadata_detector_id}" from {plugin_name} does not apply to the given package.'
    assert e_info.value.args[0].startswith(msg)
    assert "Test:Udeb-Metadata-Detector" not in plugin.substvars

    plugin.run_metadata_detector(
        metadata_detector_id,
        build_virtual_file_system(["./usr/share/doc/foo/copyright"]),
        context=package_metadata_context(package_fields={"Package-Type": "udeb"}),
    )
    assert plugin.substvars["Test:Udeb-Metadata-Detector"] == "was-run"
