"""Automatically generated module split."""

from __future__ import annotations

from typing import TYPE_CHECKING

from pyrung.core.tag import ImmediateRef, Tag

from .base import Instruction, OneShotMixin
from .resolvers import (
    resolve_coil_targets_ctx,
)

if TYPE_CHECKING:
    from pyrung.core.context import ScanContext
    from pyrung.core.memory_block import BlockRange, IndirectBlockRange


class OutInstruction(OneShotMixin, Instruction):
    """Output coil instruction (OUT).

    Sets the target bit to True when executed.
    """

    INERT_WHEN_DISABLED = False

    def __init__(
        self,
        target: Tag | BlockRange | IndirectBlockRange | ImmediateRef,
        *,
        oneshot: bool = False,
    ):
        OneShotMixin.__init__(self, oneshot)
        self.target = target

    def execute(self, ctx: ScanContext, enabled: bool) -> None:
        targets = resolve_coil_targets_ctx(self.target, ctx)
        if not enabled:
            self.reset_oneshot()
            for target in targets:
                ctx.set_tag(target.name, False)
            return

        if not self.should_execute(enabled):
            return
        for target in targets:
            ctx.set_tag(target.name, True)


class LatchInstruction(Instruction):
    """Latch/Set instruction (SET).

    Sets the target bit to True. Unlike OUT, this is typically
    not reset when the rung goes false.
    """

    def __init__(self, target: Tag | BlockRange | IndirectBlockRange | ImmediateRef):
        self.target = target

    def execute(self, ctx: ScanContext, enabled: bool) -> None:
        if not enabled:
            return
        for target in resolve_coil_targets_ctx(self.target, ctx):
            ctx.set_tag(target.name, True)


class ResetInstruction(Instruction):
    """Reset/Unlatch instruction (RST).

    Sets the target to its default value (False for bits, 0 for ints).
    """

    def __init__(self, target: Tag | BlockRange | IndirectBlockRange | ImmediateRef):
        self.target = target

    def execute(self, ctx: ScanContext, enabled: bool) -> None:
        if not enabled:
            return
        for target in resolve_coil_targets_ctx(self.target, ctx):
            ctx.set_tag(target.name, target.default)
