# Copyright 2025 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.
"""Insert additional annotations to RawResult messages."""

from __future__ import annotations

import functools
import re
from collections.abc import Callable

from recipe_engine import recipe_api

from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb
from PB.recipe_engine import result as result_pb


def _get_reasons(*exceptions: Exception) -> list[str]:
    reasons = []

    for exception in exceptions:
        if isinstance(exception, ExceptionGroup):
            for exc in exception.exceptions:
                reasons.extend(_get_reasons(exc))

        elif isinstance(exception, recipe_api.StepFailure):
            reasons.append(exception.reason)

        else:
            reasons.append(str(exception))

    return reasons


def _trim_summary_markdown(summary_markdown: str) -> str:
    summary_markdown = re.sub(r'\n\n\n+', '\n\n', summary_markdown)
    summary_markdown = re.sub(r'^\n+', '', summary_markdown)
    summary_markdown = re.sub(r'\n\n+$', '\n', summary_markdown)
    return summary_markdown


def wrap_run_steps(f: Callable[..., result_pb.RawResult | None]):
    @functools.wraps(f)
    def _wrapper(
        api: recipe_api.RecipeScriptApi,
        *args,
        **kwargs,
    ) -> result_pb.RawResult:
        experiments = [
            x
            for x in api.raw_result.buildbucket.build.input.experiments
            if x.startswith('pigweed.')
        ]

        experiment_lines: list[str] = []
        if experiments:
            experiment_lines.append('\n**Experiments**:')
            for experiment in experiments:
                experiment_lines.append(f'* {experiment}')
            experiment_lines.append('')

        experiment_part = '\n'.join(experiment_lines)

        # If we're not doing bisection and there are no experiments, then
        # there's nothing to add to the result, so directly pass through the
        # return value.
        if not api.raw_result.bisector.enabled and not experiment_part:
            return f(api, *args, **kwargs)

        infra_failure: list[Exception] = []
        step_failure: list[Exception] = []
        other_exception: list[Exception] = []

        try:
            result = f(api, *args, **kwargs)

            if not result:
                result = result_pb.RawResult(
                    summary_markdown='',
                    status=common_pb.SUCCESS,
                )

            summary_markdown = api.raw_result.bisector.summary(
                f'{result.summary_markdown}\n{experiment_part}',
            )

            return result_pb.RawResult(
                summary_markdown=_trim_summary_markdown(summary_markdown),
                status=result.status,
            )

        except* recipe_api.InfraFailure as exc:
            infra_failure.append(exc)

        except* recipe_api.StepFailure as exc:
            step_failure.append(exc)

        except* Exception as exc:
            other_exception.append(exc)

        all_exceptions = [*infra_failure, *step_failure, *other_exception]

        result: list[str] = []
        result.append('\n\n'.join(_get_reasons(*all_exceptions)))
        result.append(experiment_part)

        summary_markdown = api.raw_result.bisector.summary('\n'.join(result))

        status = common_pb.FAILURE
        if other_exception or infra_failure:
            status = common_pb.INFRA_FAILURE
        if 'LUCI CV no longer needs this Tryjob' in summary_markdown:
            status = common_pb.CANCELED

        return result_pb.RawResult(
            summary_markdown=_trim_summary_markdown(summary_markdown),
            status=status,
        )

    return _wrapper


class RawResultApi(recipe_api.RecipeApi):
    @property
    def bisector(self):
        # Don't make all recipes using this module also explicitly depend on
        # the bisector.
        return self.m.bisector

    @property
    def buildbucket(self):
        # Don't make all recipes using this module also explicitly depend on
        # the buildbucket.
        return self.m.buildbucket
