from .constants.command_types import CommandType


class Parser:
    def __init__(self, file_lines):
        """
        Constructor that takes loaded file content.

        Args:
            file_lines: List of strings (lines from the .asm file)
        """
        self.lines = file_lines
        self.current_index = -1  # Before first command
        self.current_command = ""

    def has_more_commands(self) -> bool:
        """Are there more commands to process?"""
        return self.current_index + 1 < len(self.lines)

    def advance(self) -> None:
        """Move to next command"""
        if self.has_more_commands():
            self.current_index += 1
            self.current_command = self.lines[self.current_index]

    def command_type(
        self,
    ) -> CommandType:
        """
        Returns the type of the current command.

        Returns:
            str: "A_COMMAND", "C_COMMAND", or "L_COMMAND"

        Determine command type
        """
        if self.current_command.startswith("(") and self.current_command.endswith(")"):
            label_name = self.current_command[1:-1]

            # Check 1: Not empty
            if len(label_name) == 0:
                raise ValueError("Invalid label: empty label name '()' is not allowed")

            # Check 2: No spaces (optional)
            if " " in label_name:
                raise ValueError(
                    f"Invalid label: label name cannot contain spaces: '{self.current_command}'"
                )

            # Check 3: Valid identifier (optional - letters,
            # numbers, underscore, no start with digit)
            if not label_name[0].isalpha() and label_name[0] != "_":
                raise ValueError(
                    f"Invalid label: label must start with letter or underscore: '{self.current_command}'"
                )

            return CommandType.L_COMMAND
        elif self.current_command.startswith("@"):
            return CommandType.A_COMMAND
        else:
            return CommandType.C_COMMAND

    def symbol(self) -> str:
        """Get symbol from A-command or L-command"""
        if self.current_command.startswith("@"):
            return self.current_command[1:]
        elif self.current_command.startswith("("):
            return self.current_command[1:-1]
        return ""

    def reset_index(self) -> None:
        """Resset the current index"""
        self.current_index = -1

    def dest(self) -> str:
        """Returns the dest mnemonic in the current C-command."""
        if "=" in self.current_command:
            # Get everything up to the = sign
            return self.current_command[: self.current_command.index("=")]
        else:
            return ""

    def comp(self) -> str:
        """Returns the comp mnemonic in the current C-command."""
        # Start with the full command
        comp_part = self.current_command

        # Remove dest part (everything before and including =)
        if "=" in comp_part:
            comp_part = comp_part[comp_part.index("=") + 1 :]

        # Remove jump part (everything from and including ;)
        if ";" in comp_part:
            comp_part = comp_part[: comp_part.index(";")]

        return comp_part

    def jump(self) -> str:
        """Returns the jump mnemonic in the current C-command."""
        if ";" in self.current_command:
            # Get everything after the ; sign
            return self.current_command[self.current_command.index(";") + 1 :]
        else:
            return ""
