# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from __future__ import annotations

from enum import Enum
from functools import cached_property

from pants.option.option_types import BoolOption, EnumOption, StrListOption
from pants.option.subsystem import Subsystem
from pants.util.strutil import softwrap


class UnownedHelmDependencyUsage(Enum):
    """What action to take when an inferred dependency is unowned."""

    RaiseError = "error"
    LogWarning = "warning"
    DoNothing = "ignore"


class UnownedDependencyError(Exception):
    """The inferred dependency does not have any owner."""


class HelmInferSubsystem(Subsystem):
    """Settings controlling the dependency inference behaviour of the Helm backend.

    Adding "*" to `external_docker_images` is different from setting `unowned_dependency_behavior`
    to something other than "error". The key is that `external_docker_images` with "*" will only
    allow anything that could be a docker image, but will still raise errors for other inference
    problems.
    """

    options_scope = "helm-infer"
    help = "Options controlling which dependencies will be inferred for Helm targets."

    unowned_dependency_behavior = EnumOption(
        default=UnownedHelmDependencyUsage.RaiseError,
        help=softwrap(
            """
            How to handle inferred dependencies that don't have an inferable owner.

            Usually when an import cannot be inferred, it represents an issue like Pants not being
            properly configured, e.g. targets not set up. Often, missing dependencies will result
            in confusing runtime errors where Docker images haven't been published,
            so this option can be helpful to error more eagerly.
            """
        ),
    )

    external_docker_images = StrListOption(
        default=[],
        help=softwrap(
            """
            Docker image names that are not provided by targets in this repository
            and should be ignored for calculating dependencies.

            For example, adding `python` to this setting
            will cause Pants to not try to find the target `python:3.10`
            in the following `helm_deployment`:

            ```
            helm_deployment(
                name="my-deployment",
                chart=":mychart",
                values={"container.image_ref": "python:3.10"},
            )
            ```

            Use Python fnmatch glob syntax (ex: 'docker.io/*') to disable this
            check for certain images or patterns.  This will limit Pants's
            ability to warn on unknown docker images.
            """
        ),
    )

    deployment_dependencies = BoolOption(
        default=True,
        help="If true, parse k8s manifests generated by helm to find dependencies on other targets like docker images.",
        advanced=True,
    )

    @cached_property
    def external_base_images(self) -> set[str]:
        return set(self.external_docker_images)
