load("@aspect_rules_swc//swc:swc.bzl", "swc_rule")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("@npm//@bazel/typescript:index.bzl", _ts_config = "ts_config", _ts_project = "ts_project")
load("//tools/web:package.bzl", pkg_name = "package_name")
load("//tools:conditions.bzl", "if_opt_build")

_TS_LIBRARY_DEPS = ["@npm//@types/node", "@npm//@types/jest", "@npm//tslib"]

def pl_ts_library(
        name,
        srcs,
        deps = [],
        peer_typed_deps = [],
        tsconfig = "//:tsconfig",
        **kwargs):
    """A TypeScript library.

    This rule doesn't run `tsc` when building the library, relying on `swc`
    instead, providing typecheck as test. This ensures that the fast path is
    fast. The generated test is names as `<name>_typecheck`.

    Args:
        name (string): name of target. This will also be used to generate the JS import name.
        srcs (list): list of sources of this target.
        deps (list): list of dependencies of this target.
        peer_typed_deps (list): list of dependencies of this target that need `@types` packages
            to be typed. E.g. jest.
        tsconfig (string): the tsconfig.json label.
        **kwargs: any extra rule argument (tags, visibility, etc.).
    """
    deps = deps + _peer_typed_deps(peer_typed_deps)

    package_name = pkg_name(name)
    ts_proj = "%s.ts" % js_lib
    _pl_ts_project(
        name = js_lib,
        srcs = srcs,
        deps = deps,
        tsconfig = tsconfig,
        package_name = package_name,
        **kwargs
    )

def _pl_ts_project(name, deps, package_name, tsconfig, root_dir, **kwargs):
    srcs = kwargs.pop("srcs")

    ts_proj = name + ".ts"
    _ts_project(
        name = ts_proj,
        srcs = srcs,
        deps = deps + _TS_LIBRARY_DEPS,
        transpiler = _transpiler,
        tsconfig = tsconfig,
        root_dir = None,
        # Disabling tsconfig validation speeds up the build, but we need to
        # keep the arguments in sync with the tsconfig file
        validate = False,
        composite = True,
        declaration = True,
        declaration_map = True,
        source_map = False,
        allow_js = False,
        supports_workers = False,
        incremental = True,
        resolve_json_module = True,
        data = kwargs.pop("data", []),
        **kwargs
    )

    js_library(
        name = name,
        deps = [ts_proj],
        package_name = package_name,
        **kwargs,
    )

    native.alias(
        name = name + "_typecheck",
        actual = ts_proj + "_typecheck",
    )

def _peer_typed_deps(args):
    return args + [a.replace("@npm//", "@npm//@types/") for a in args]

def _transpiler(**kwargs):
    def as_config_args(**args):
        args = []
        for key, value in args.items():
            args.append("-C")
            args.append("{}={}".format(key, value))

        return args

    define_global_debug = "jsc.transform.optimizer.globals.var.__DEBUG__"

    opt_args = {
        define_global_debug: "false",
        "minify": "true",
        "sourceMaps": "false",
    }

    fastbuild_args = {
        define_global_debug: "true",
        "minify": "false",
        "sourceMaps": "true",
    }

    swc_rule(
        swcrc = "//tools/web:swcrc.json",
        args = if_opt_build(as_config_args(opt_args), as_config_args(fastbuild_args)),
        **kwargs
    )
