# 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.
"""Split combined triggers into separate builds by branch."""

from __future__ import annotations

import dataclasses
import urllib.parse
from typing import Any

from recipe_engine import recipe_api

from PB.go.chromium.org.luci.buildbucket.proto import (
    builds_service as builds_service_pb,
)
from PB.go.chromium.org.luci.buildbucket.proto import common as common_pb
from PB.go.chromium.org.luci.scheduler.api.scheduler.v1 import (
    triggers as triggers_pb,
)
from PB.recipe_engine import result as result_pb
from PB.recipe_modules.pigweed.split_triggers.properties import InputProperties


@dataclasses.dataclass(frozen=True)
class RemoteBranch:
    remote: str
    ref: str


class SplitTriggersApi(recipe_api.RecipeApi):
    """Split combined triggers into separate builds by branch."""

    def __init__(self, props: InputProperties, *args: Any, **kwargs: Any):
        super().__init__(*args, **kwargs)
        self._props = props

    def __call__(self) -> result_pb.RawResult | None:
        """Split combined triggers into separate builds by branch."""
        with self.m.step.nest('split triggers'):
            return self._split()

    def _split(self) -> result_pb.RawResult | None:
        pres = self.m.step.empty('properties').presentation
        pres.step_summary_text = repr(self.m.properties.thaw())

        with self.m.step.nest('processing triggers'):
            triggers_by_branch: dict[
                RemoteBranch, list[triggers_pb.Trigger]
            ] = {}
            for trigger in self.m.scheduler.triggers:
                if trigger.WhichOneof('payload') != 'gitiles':
                    self.m.step.empty('one non-gitiles trigger')
                    continue

                key = RemoteBranch(trigger.gitiles.repo, trigger.gitiles.ref)
                self.m.step.empty(
                    f'one trigger for {key.remote} {key.ref} '
                    f'{trigger.gitiles.revision}',
                )
                triggers_by_branch.setdefault(key, [])
                triggers_by_branch[key].append(trigger)

        requests: list[builds_service_pb.ScheduleBuildRequest] = []

        schedule_kwargs = {}
        schedule_kwargs['builder'] = self.m.buildbucket.build.builder.builder
        schedule_kwargs['inherit_buildsets'] = False
        schedule_kwargs['experiments'] = {'pigweed.disable_git_cache': True}
        schedule_kwargs['can_outlive_parent'] = True

        num_branches = len(triggers_by_branch)

        if num_branches == 0:
            self.m.step.empty('no branches')
            return None

        if num_branches == 1:
            self.m.step.empty('only one branch')
            return None

        with self.m.step.nest('filtering'):
            for triggers in triggers_by_branch.values():
                # The most recent commit on a branch shows up last in the
                # list of commits, so we only need to trigger the build on
                # it.
                trigger = triggers[-1].gitiles
                parsed = urllib.parse.urlparse(trigger.repo)

                commit = common_pb.GitilesCommit(
                    host=parsed.hostname,
                    project=parsed.path.lstrip('/'),
                    id=trigger.revision,
                    ref=trigger.ref,
                )

                requests.append(
                    self.m.buildbucket.schedule_request(
                        gitiles_commit=commit,
                        **schedule_kwargs,
                    )
                )
                self.m.step.empty(
                    f'selected {trigger.repo} {trigger.ref} {trigger.revision}',
                )

        with self.m.step.nest(f'launching {len(requests)} builds'):
            if self._props.enabled:
                summary = [
                    f'Split the triggers into {len(requests)} based on trigger '
                    'branches',
                ]
                builds = self.m.buildbucket.schedule(requests)

                for build in builds:
                    branch = build.input.gitiles_commit.ref.removeprefix(
                        'refs/heads/',
                    )
                    summary.append(
                        f'* {branch}: {self.m.buildbucket.build_url(build=build)}',
                    )

                return result_pb.RawResult(
                    summary_markdown='\n'.join(summary),
                    status=common_pb.SUCCESS,
                )

            else:
                self.m.step.empty('dry-run')

                for request in requests:
                    branch = request.gitiles_commit.ref.removeprefix(
                        'refs/heads/',
                    )
                    self.m.step.empty(branch)

                return None
