# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2011-2024 Blender Authors
# <pep8 compliant>

import importlib
import os
import sys
import re
import pathlib

import buildbot.plugins

from typing import Any, Dict, List

sys.path.append(str(pathlib.Path(__file__).resolve().parent))

import conf.auth
import conf.branches
import conf.machines
import conf.worker

import gitea.blender

import pipeline

# We need to do this when we reload (SIGHUP) the buildbot server process.
importlib.reload(conf.auth)
importlib.reload(conf.branches)
importlib.reload(conf.machines)
importlib.reload(conf.worker)
importlib.reload(gitea.blender)
importlib.reload(pipeline)

environment = os.environ.get("BUILDBOT_environment", default="LOCAL")


def setup() -> Dict[str, Any]:
    ####### CONFIGURATION
    c = {}

    # Change Source
    c["change_source"] = pipeline.change_sources()

    # Workers
    print("*** Creating platform workers")
    platform_worker_names = conf.machines.fetch_platform_worker_names(environment)
    workers: List[buildbot.plugins.worker.Worker] = []
    configured_worker_names = set()
    for worker_names in platform_worker_names.values():
        for worker_name in worker_names:
            if worker_name in configured_worker_names:
                print(f"Skipping {worker_name}, already configured")
                continue
            configured_worker_names.add(worker_name)
            workers += [
                buildbot.plugins.worker.Worker(
                    worker_name,
                    conf.machines.get_worker_password(environment, worker_name),
                    max_builds=1,
                    keepalive_interval=3600,
                )
            ]

    print("*** Creating local workers")
    local_worker_names = conf.machines.fetch_local_worker_names()
    for worker_name in local_worker_names:
        workers += [buildbot.plugins.worker.LocalWorker(worker_name)]

    c["workers"] = workers

    # Builders and Schedulers
    builders, schedulers = pipeline.populate(environment)
    c["builders"] = builders
    c["schedulers"] = schedulers

    ####### BUILDBOT SERVICES

    # 'services' is a list of BuildbotService items like reporter targets. The
    # status of each build will be pushed to these targets. buildbot/reporters/*.py
    # has a variety to choose from, like IRC bots.

    gitea_status_service = gitea.blender.setup_service(environment)
    if gitea_status_service:
        c["services"] = [gitea_status_service]
    else:
        c["services"] = []

    ####### PROJECT IDENTITY

    # the 'title' string will appear at the top of this buildbot installation's
    # home pages (linked to the 'titleURL').

    c["title"] = f"Blender Buildbot - {environment}"
    c["titleURL"] = "https://projects.blender.org"

    # the 'buildbotURL' string should point to the location where the buildbot's
    # internal web server is visible. This typically uses the port number set in
    # the 'www' entry below, but with an externally-visible host name which the
    # buildbot cannot figure out without some help.
    c["buildbotURL"] = os.environ.get("BUILDBOT_WEB_URL", "http://localhost:8010/")

    # Minimalistic config to activate new web UI
    c["www"] = dict(
        port=os.environ.get("BUILDBOT_WEB_PORT", 8010),
        plugins=dict(waterfall_view={}, console_view={}, grid_view={}),
    )

    # Database
    c["db"] = {
        "db_url": os.environ.get("BUILDBOT_DB_URL", "sqlite://").format(**os.environ)
    }

    c["buildbotNetUsageData"] = None

    # Authentication
    c["www"]["auth"] = conf.auth.fetch_authentication(environment)

    # Authorization
    c["www"]["authz"] = conf.auth.fetch_authorization(environment)

    # Disable UI - does not work
    c["www"]["plugins"] = {
        "waterfall_view": False,
        "console_view": False,
        "grid_view": False,
    }

    # UI Defaults
    c["www"]["ui_default_config"] = {
        "Grid.fullChanges": True,
        "Grid.leftToRight": True,
        "Grid.revisionLimit": 10,
        "Builders.buildFetchLimit": 400,
        "LogPreview.loadlines": 100,
        "LogPreview.maxlines": 100,
        "ChangeBuilds.buildsFetchLimit": 10,
    }

    # Validation
    c["validation"] = {
        "branch": re.compile(r"^[\w.+/~-]*$"),
        "revision": re.compile(r"^[ \w\.\-\/]*$"),
        "property_name": re.compile(r"^[\w\.\-\/\~:]*$"),
        "property_value": re.compile(r"^[\w\.\-\/\~:]*$"),
    }

    # Rev link
    c["revlink"] = buildbot.plugins.util.RevlinkMatch(
        [r"https://projects.blender.org/([^/]*)/([^/]*?)(?:\.git)?$"],
        r"https://projects.blender.org/\1/\2/commit/%s",
    )

    # Port for workers to connect to
    c["protocols"] = {"pb": {"port": os.environ.get("BUILDBOT_WORKER_PORT", 9989)}}

    # Disable collapsing requests
    c["collapseRequests"] = False

    return c