"""Dev-session rules for Bun-backed Wails apps."""

load("//wails:private/common.bzl", "bash_launcher")

def _shell_quote(value):
    return "'" + value.replace("'", "'\"'\"'") + "'"

def _absolute_label(label_package, name):
    if label_package:
        return "//%s:%s" % (label_package, name)
    return "//:%s" % name

def _wails_bun_watch_run_impl(ctx):
    launcher = ctx.actions.declare_file(ctx.label.name)

    resolve_lines = """
tool="$(resolve_runfile "{tool_short_path}")"
binary="$(resolve_runfile "{binary_short_path}")"
build_assets="$(resolve_runfile "{build_assets_short_path}")"
bindings=""
if [[ -n "{bindings_short_path}" ]]; then
  bindings="$(resolve_runfile "{bindings_short_path}")"
fi
icon=""
if [[ -n "{icon_short_path}" ]]; then
  icon="$(resolve_runfile "{icon_short_path}")"
fi
""".format(
        tool_short_path = ctx.executable._tool.short_path,
        binary_short_path = ctx.executable.binary.short_path,
        build_assets_short_path = ctx.files.build_assets[0].short_path,
        bindings_short_path = ctx.executable.bindings.short_path if ctx.executable.bindings else "",
        icon_short_path = ctx.file.icon.short_path if ctx.file.icon else "",
    )

    binding_command = ""
    if ctx.executable.bindings:
        binding_command = "\"$bindings\"\n"

    command_lines = """
{binding_command}exec "$tool" \
  --binary "$binary" \
  --build-assets "$build_assets" \
  --frontend-url {frontend_url} \
  --icon "$icon" \
  --mode 'dev'
""".format(
        binding_command = binding_command,
        frontend_url = _shell_quote(ctx.attr.frontend_url),
    )

    ctx.actions.write(
        output = launcher,
        is_executable = True,
        content = bash_launcher(resolve_lines, command_lines),
    )

    transitive_files = [
        ctx.attr._tool[DefaultInfo].default_runfiles.files,
        ctx.attr.binary[DefaultInfo].default_runfiles.files,
    ]
    files = [
        ctx.executable._tool,
        ctx.executable.binary,
    ] + ctx.files.build_assets + ([ctx.file.icon] if ctx.file.icon else [])

    if ctx.attr.bindings:
        transitive_files.append(ctx.attr.bindings[DefaultInfo].default_runfiles.files)
        files.append(ctx.executable.bindings)

    runfiles = ctx.runfiles(
        files = files,
        transitive_files = depset(transitive = transitive_files),
    )

    return [DefaultInfo(executable = launcher, runfiles = runfiles)]

_wails_bun_watch_run = rule(
    implementation = _wails_bun_watch_run_impl,
    attrs = {
        "binary": attr.label(
            mandatory = True,
            executable = True,
            cfg = "target",
        ),
        "bindings": attr.label(
            executable = True,
            cfg = "target",
        ),
        "build_assets": attr.label(
            mandatory = True,
            allow_files = True,
        ),
        "frontend_url": attr.string(default = "http://127.0.0.1:9245"),
        "icon": attr.label(allow_single_file = True),
        "_tool": attr.label(
            default = "//wails/tools:launch_app",
            cfg = "exec",
            executable = True,
        ),
    },
    executable = True,
)

def _wails_bun_dev_session_impl(ctx):
    launcher = ctx.actions.declare_file(ctx.label.name)
    resolve_lines = """
tool="$(resolve_runfile "{tool_short_path}")"
frontend_dev="$(resolve_runfile "{frontend_dev_short_path}")"
""".format(
        tool_short_path = ctx.executable._tool.short_path,
        frontend_dev_short_path = ctx.executable.frontend_dev.short_path,
    )

    command_lines = """
exec "$tool" \
  --frontend-dev "$frontend_dev" \
  --frontend-url {frontend_url} \
  --watch-target {watch_target} \
  --workspace-dir {workspace_dir}
""".format(
        frontend_url = _shell_quote(ctx.attr.frontend_url),
        watch_target = _shell_quote(ctx.attr.watch_target),
        workspace_dir = _shell_quote(ctx.attr.workspace_dir),
    )

    ctx.actions.write(
        output = launcher,
        is_executable = True,
        content = bash_launcher(resolve_lines, command_lines),
    )

    runfiles = ctx.runfiles(
        files = [
            ctx.executable._tool,
            ctx.executable.frontend_dev,
        ],
        transitive_files = depset(transitive = [
            ctx.attr._tool[DefaultInfo].default_runfiles.files,
            ctx.attr.frontend_dev[DefaultInfo].default_runfiles.files,
        ]),
    )

    return [DefaultInfo(executable = launcher, runfiles = runfiles)]

_wails_bun_dev_session_rule = rule(
    implementation = _wails_bun_dev_session_impl,
    attrs = {
        "frontend_dev": attr.label(
            mandatory = True,
            executable = True,
            cfg = "target",
        ),
        "frontend_url": attr.string(default = "http://127.0.0.1:9245"),
        "watch_target": attr.string(mandatory = True),
        "workspace_dir": attr.string(default = "."),
        "_tool": attr.label(
            default = "//wails_bun/tools:bun_dev_session",
            cfg = "exec",
            executable = True,
        ),
    },
    executable = True,
)

def wails_bun_dev_session(
        name,
        workspace_dir,
        frontend_dev,
        app_binary,
        build_assets,
        bindings_target = None,
        icon = None,
        frontend_url = "http://127.0.0.1:9245",
        tags = None,
        visibility = None):
    watch_name = name + "_watch"

    _wails_bun_watch_run(
        name = watch_name,
        binary = app_binary,
        bindings = bindings_target,
        build_assets = build_assets,
        frontend_url = frontend_url,
        icon = icon,
        tags = ["manual"],
        visibility = ["//visibility:private"],
    )

    _wails_bun_dev_session_rule(
        name = name,
        frontend_dev = frontend_dev,
        frontend_url = frontend_url,
        tags = tags,
        visibility = visibility,
        watch_target = _absolute_label(native.package_name(), watch_name),
        workspace_dir = workspace_dir,
    )
