# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""General purpose tools for running presubmit checks."""

import collections
from collections import Counter, defaultdict
import logging
import os
from pathlib import Path
import shlex
import subprocess
from typing import Any, Dict, Iterable, Iterator, List, Sequence, Pattern, Tuple

_LOG: logging.Logger = logging.getLogger(__name__)


def plural(items_or_count,
           singular: str,
           count_format='',
           these: bool = False,
           number: bool = True,
           are: bool = False) -> str:
    """Returns the singular or plural form of a word based on a count."""

    try:
        count = len(items_or_count)
    except TypeError:
        count = items_or_count

    prefix = ('this ' if count == 1 else 'these ') if these else ''
    num = f'{count:{count_format}} ' if number else ''
    suffix = (' is' if count == 1 else ' are') if are else ''

    if singular.endswith('y'):
        result = f'{singular[:-1]}{"y" if count == 1 else "ies"}'
    elif singular.endswith('s'):
        result = f'{singular}{"" if count == 1 else "es"}'
    else:
        result = f'{singular}{"" if count == 1 else "s"}'

    return f'{prefix}{num}{result}{suffix}'


def make_color(*codes: int):
    start = ''.join(f'\033[{code}m' for code in codes)
    return f'{start}{{}}\033[0m'.format if os.name == 'posix' else str


def make_box(section_alignments: Sequence[str]) -> str:
    indices = [i + 1 for i in range(len(section_alignments))]
    top_sections = '{2}'.join('{1:{1}^{width%d}}' % i for i in indices)
    mid_sections = '{5}'.join('{section%d:%s{width%d}}' %
                              (i, section_alignments[i - 1], i)
                              for i in indices)
    bot_sections = '{9}'.join('{8:{8}^{width%d}}' % i for i in indices)

    return ''.join(['{0}', *top_sections, '{3}\n',
                    '{4}', *mid_sections, '{6}\n',
                    '{7}', *bot_sections, '{10}'])  # yapf: disable


def file_summary(paths: Iterable[Path],
                 levels: int = 2,
                 max_lines: int = 12,
                 max_types: int = 3,
                 pad: str = ' ',
                 pad_start: str = ' ',
                 pad_end: str = ' ') -> List[str]:
    """Summarizes a list of files by the file types in each directory."""

    # Count the file types in each directory.
    all_counts: Dict[Any, Counter] = defaultdict(Counter)

    for path in paths:
        parent = path.parents[max(len(path.parents) - levels, 0)]
        all_counts[parent][path.suffix] += 1

    # If there are too many lines, condense directories with the fewest files.
    if len(all_counts) > max_lines:
        counts = sorted(all_counts.items(),
                        key=lambda item: -sum(item[1].values()))
        counts, others = sorted(counts[:max_lines - 1]), counts[max_lines - 1:]
        counts.append((f'({plural(others, "other")})',
                       sum((c for _, c in others), Counter())))
    else:
        counts = sorted(all_counts.items())

    width = max(len(str(d)) + len(os.sep) for d, _ in counts) if counts else 0
    width += len(pad_start)

    # Prepare the output.
    output = []
    for path, files in counts:
        total = sum(files.values())
        del files['']  # Never display no-extension files individually.

        if files:
            extensions = files.most_common(max_types)
            other_extensions = total - sum(count for _, count in extensions)
            if other_extensions:
                extensions.append(('other', other_extensions))

            types = ' (' + ', '.join(f'{c} {e}' for e, c in extensions) + ')'
        else:
            types = ''

        root = f'{path}{os.sep}{pad_start}'.ljust(width, pad)
        output.append(f'{root}{pad_end}{plural(total, "file")}{types}')

    return output


def relative_paths(paths: Iterable[Path], start: Path) -> Iterable[Path]:
    """Returns relative Paths calculated with os.path.relpath."""
    for path in paths:
        yield Path(os.path.relpath(path, start))


def exclude_paths(exclusions: Iterable[Pattern[str]],
                  paths: Iterable[Path],
                  relative_to: Path = None) -> Iterable[Path]:
    """Excludes paths based on a series of regular expressions."""
    if relative_to:
        relpath = lambda path: Path(os.path.relpath(path, relative_to))
    else:
        relpath = lambda path: path

    for path in paths:
        if not any(e.search(relpath(path).as_posix()) for e in exclusions):
            yield path


def _truncate(value, length: int = 60) -> str:
    value = str(value)
    return (value[:length - 5] + '[...]') if len(value) > length else value


def format_command(args: Sequence, kwargs: dict) -> Tuple[str, str]:
    attr = ', '.join(f'{k}={_truncate(v)}' for k, v in sorted(kwargs.items()))
    return attr, shlex.join(str(arg) for arg in args)


def log_run(args, **kwargs) -> subprocess.CompletedProcess:
    """Logs a command then runs it with subprocess.run.

    Takes the same arguments as subprocess.run.
    """
    _LOG.debug('[COMMAND] %s\n%s', *format_command(args, kwargs))
    return subprocess.run(args, **kwargs)


def flatten(*items) -> Iterator:
    """Yields items from a series of items and nested iterables.

    This function is used to flatten arbitrarily nested lists. str and bytes
    are kept intact.
    """

    for item in items:
        if isinstance(item, collections.abc.Iterable) and not isinstance(
                item, (str, bytes)):
            yield from flatten(*item)
        else:
            yield item
