""" Custom Ansible Lookup Plugin for reading dotenv files.

Ansible officially supports Python 2.7 and 3.5+, but this requires Python 3.8+.

"""
from __future__ import annotations

from typing import Sequence

from ansible.errors import AnsibleFileNotFound, AnsibleLookupError
from ansible.plugins.lookup import LookupBase
from re import compile


__all__ = "DOCUMENTATION", "EXAMPLES", "RETURN", "LookupModule"


# Options not documented will be ignored during processing.

DOCUMENTATION = """
  name: dotenv
  author:
    - Michael Klatt <mdklatt(at)alumni.ou.edu>
  short_description: Retrieve values from dotenv files
  requirements:
    - Anisble must be running under Python 3.8+.
  description:
    - Retrieve values from dotenv values.
  seealso:
    - name: RFC 2 - .env file
      description: Smartmob RFC for a .env file standard
      link: https://smartmob-rfc.readthedocs.io/en/latest/2-dotenv.html
  notes:
    - The RFC 2 continuation line syntax is not yet supported.
  options:
    _terms:
      description: The key(s) to look up.
      required: True
    file:
      description: Path to the dotenv file.
      default: '.env'
"""  # YAML


RETURN = """
  _raw:
    description:
      - value(s) of the search term(s) in the dotenv file
    type: list
    elements: str
"""  # YAML


EXAMPLES = """
  - name: Retrieve value from the .env file in the current working directory.
    debug:
      msg: "{{ lookup('dotenv', 'VAR') }}"
  - name: Use a non-default dotenv file.
    debug:
      msg: "{{ lookup('dotenv', 'VAR', file='path/to/.env') }}"
"""  # YAML


class LookupModule(LookupBase):  # class name is not arbitrary, DO NOT CHANGE
    """ Look up values from a dotenv file.

    """
    def run(self, terms: Sequence[str], variables=None, **options) -> list:
        """ Execute the lookup.

        :param terms: search terms
        :param variables: mapping of defined Ansible variables
        :param options: options passed directly as keyword arguments
        :return: list of found values
        """
        # Adapted from 'ansible.builtin.ini' lookup.
        # <https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/lookup/ini.py>
        # <https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#developing-lookup-plugins>
        self.set_options(var_options=variables, direct=options)
        params = self.get_options()
        path = self.find_file_in_search_path(variables, "files", params["file"])
        if not path:
            raise AnsibleFileNotFound(f"Could not find file {params['file']}")
        var_pattern = compile(r"^\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*(\S*)")
        variables = {}
        for line in open(path, "rt").readlines():
            # Parse the dotenv file permissively, accepting valid NAME=VALUE
            # lines while ignoring everything else.
            # TODO: Support RFC 2 line continuation syntax.
            if match := var_pattern.match(line):
                variables[match.group(1)] = match.group(2)
        try:
            return [variables[key] for key in terms]
        except KeyError as err:
            key = err.args[0]
            raise AnsibleLookupError(f"No value for '{key}' in {path}")