"""Find task for ScriptEngine"""

import fnmatch
import os

from scriptengine.context import ContextUpdate
from scriptengine.exceptions import ScriptEngineTaskArgumentInvalidError
from scriptengine.tasks.core import Task, timed_runner


class Find(Task):
    """Find task, finds files or directories by name patterns"""

    _required_arguments = ("path",)

    def __init__(self, arguments):
        Find.check_arguments(arguments)
        super().__init__(arguments)

    @timed_runner
    def run(self, context):
        path = os.path.normpath(self.getarg("path", context))
        path_depth = path.count(os.path.sep)

        pattern = self.getarg("pattern", context, default="*")

        find_type = self.getarg("type", context, default="file")
        if find_type not in ("file", "dir"):
            msg = (
                f'Invalid "type" argument '
                f'(must be either "file" or "dir"): {find_type}'
            )
            self.log_error(msg)
            raise ScriptEngineTaskArgumentInvalidError(msg)

        max_depth = self.getarg("depth", context, default=-1)
        try:
            max_depth = max(-1, int(max_depth))
        except (ValueError, TypeError):
            msg = f'Invalid "depth" argument (not an integer): {max_depth}'
            self.log_error(msg)
            raise ScriptEngineTaskArgumentInvalidError(msg)

        self.log_info(
            f'Find {find_type} with pattern "{pattern}" '
            f"in {path} (with max depth={max_depth})"
        )
        result = []
        for root, dirs, files in os.walk(path):
            if find_type == "file":
                files_or_dirs = files
            else:
                files_or_dirs = dirs
            for name in files_or_dirs:
                if fnmatch.fnmatch(name, pattern):
                    result.append(os.path.normpath(os.path.join(root, name)))
            if max_depth >= 0 and root.count(os.path.sep) >= path_depth + max_depth:
                del dirs[:]
        if result:
            self.log_debug(f"Found: {result}")
        else:
            self.log_debug("Nothing found")
        result_key = self.getarg("set", context, default="result")
        self.log_debug(f'Store result under context key "{result_key}"')

        return ContextUpdate({result_key: result})
