import textwrap

import pytest

from debputy.highlevel_manifest_parser import YAMLManifestParser
from debputy.manifest_parser.exceptions import ManifestParseException
from debputy.plugin.api.test_api import build_virtual_file_system


@pytest.fixture()
def manifest_parser_pkg_foo(
    amd64_dpkg_architecture_variables,
    dpkg_arch_query,
    package_single_foo_arch_all_cxt_amd64,
    null_substitution,
    no_profiles_or_build_options,
    debputy_plugin_feature_set,
) -> YAMLManifestParser:
    # We need an empty directory to avoid triggering packager provided files.
    debian_dir = build_virtual_file_system([])
    return YAMLManifestParser(
        "debian/test-debputy.manifest",
        package_single_foo_arch_all_cxt_amd64,
        null_substitution,
        amd64_dpkg_architecture_variables,
        dpkg_arch_query,
        no_profiles_or_build_options,
        debputy_plugin_feature_set,
        debian_dir=debian_dir,
    )


def test_parsing_no_manifest(manifest_parser_pkg_foo):
    manifest = manifest_parser_pkg_foo.build_manifest()

    assert [p.name for p in manifest.all_packages] == ["foo"]
    assert [p.name for p in manifest.active_packages] == ["foo"]


def test_parsing_version_only(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    """
    )

    manifest = manifest_parser_pkg_foo.parse_manifest(fd=content)

    assert [p.name for p in manifest.all_packages] == ["foo"]
    assert [p.name for p in manifest.active_packages] == ["foo"]


def test_parsing_package_foo_empty(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        foo:
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    assert "The attribute packages.foo must be a mapping." in e_info.value.args[0]


def test_parsing_package_bar_empty(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        bar:
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    assert 'package "bar" is not present' in e_info.value.args[0]


def test_transformations_no_list(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        foo:
            transformations:
              create-symlinks:
                 path: a
                 target: b
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    assert "packages.foo.transformations" in e_info.value.args[0]
    assert "must be a list" in e_info.value.args[0]


def test_create_symlinks_missing_path(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        foo:
            transformations:
              - create-symlink:
                  target: b
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    msg = "The following keys were required but not present at packages.foo.transformations[0].create-symlink: 'path'"
    assert e_info.value.args[0] == msg


def test_create_symlinks_missing_target(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        foo:
            transformations:
              - create-symlink:
                  path: a
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    msg = "The following keys were required but not present at packages.foo.transformations[0].create-symlink: 'target'"
    assert e_info.value.args[0] == msg


def test_create_symlinks_not_normalized_path(manifest_parser_pkg_foo):
    content = textwrap.dedent(
        """\
    manifest-version: '0.1'
    packages:
        foo:
            transformations:
              - create-symlink:
                  path: ../bar
                  target: b
    """
    )

    with pytest.raises(ManifestParseException) as e_info:
        manifest_parser_pkg_foo.parse_manifest(fd=content)

    expected = (
        'The path "../bar" provided in packages.foo.transformations[0].create-symlink.path <Search for: ../bar>'
        ' should be relative to the root of the package and not use any ".." or "." segments.'
    )
    assert e_info.value.args[0] == expected
