"""SLURM output formatter for squeue and other commands."""

import re
from typing import Any, Dict, List, Optional


class SlurmOutputFormatter:
    """Format output for SLURM commands like squeue."""

    # Default squeue format
    DEFAULT_FORMAT = "%.18i %.9P %.8j %.8u %.2t %.10M %.6D %R"

    # Format specifier mappings
    FORMAT_SPECS = {
        # Job identifiers
        "i": ("JOBID", "Job ID", "left"),
        "A": ("JOBID", "Job ID", "right"),  # Right-aligned
        "j": ("NAME", "Job name", "left"),
        # Partition and QoS
        "P": ("PARTITION", "Partition", "left"),
        "q": ("QOS", "QoS", "left"),
        # User and group
        "u": ("USER", "User", "left"),
        "g": ("GROUP", "Group", "left"),
        # State and time
        "t": ("ST", "State", "left"),
        "T": ("STATE", "State long", "left"),
        "M": ("TIME", "Time used", "right"),
        "l": ("TIME_LIMIT", "Time limit", "right"),
        "S": ("START_TIME", "Start time", "left"),
        "e": ("END_TIME", "End time", "left"),
        # Resources
        "D": ("NODES", "Nodes", "right"),
        "C": ("CPUS", "CPUs", "right"),
        "m": ("MIN_MEMORY", "Min memory", "right"),
        # Node info
        "R": ("NODELIST(REASON)", "Nodelist/Reason", "left"),
        "r": ("REASON", "Reason", "left"),
        "E": ("DEPENDENCY", "Dependency", "left"),
        # Array jobs
        "F": ("ARRAY_JOB_ID", "Array job ID", "right"),
        "K": ("ARRAY_TASK_ID", "Array task ID", "right"),
    }

    def __init__(self, format_spec: Optional[str] = None):
        """Initialize formatter with format specification.

        Args:
            format_spec: SLURM format string (e.g., "%.18i %.9P %.8j")
        """
        self.format_spec = format_spec or self.DEFAULT_FORMAT
        self.columns = self._parse_format_spec(self.format_spec)

    def _parse_format_spec(self, format_spec: str) -> List[Dict[str, Any]]:
        """Parse SLURM format specification.

        Args:
            format_spec: Format string

        Returns:
            List of column specifications
        """
        columns = []

        # Pattern to match format specifiers like %.18i or %20j
        pattern = r"%(\.)?(\\d*)(\\w)"

        for match in re.finditer(pattern, format_spec):
            dot = match.group(1)  # Optional dot for truncation
            width = match.group(2)  # Optional width
            spec = match.group(3)  # Format character

            if spec in self.FORMAT_SPECS:
                field, header, align = self.FORMAT_SPECS[spec]

                col_spec = {
                    "field": field,
                    "header": header,
                    "align": align,
                    "width": int(width) if width else None,
                    "truncate": bool(dot),
                }

                columns.append(col_spec)

        return columns

    def format_job_list(self, jobs: List[Dict[str, Any]], noheader: bool = False) -> str:
        """Format list of jobs according to format specification.

        Args:
            jobs: List of job dictionaries
            noheader: Whether to skip header line

        Returns:
            Formatted output string
        """
        if not self.columns:
            return ""

        lines = []

        # Build header if needed
        if not noheader:
            header_parts = []
            for col in self.columns:
                header = col["header"]
                width = col["width"]

                if width:
                    if col["align"] == "right":
                        header_parts.append(header.rjust(width))
                    else:
                        header_parts.append(header.ljust(width))
                else:
                    header_parts.append(header)

            lines.append(" ".join(header_parts))

        # Format each job
        for job in jobs:
            row_parts = []

            for col in self.columns:
                value = str(job.get(col["field"], ""))
                width = col["width"]

                if width:
                    if col["truncate"] and len(value) > width:
                        value = value[:width]

                    if col["align"] == "right":
                        row_parts.append(value.rjust(width))
                    else:
                        row_parts.append(value.ljust(width))
                else:
                    row_parts.append(value)

            lines.append(" ".join(row_parts))

        return "\\n".join(lines) + "\\n"

    def format_job_details(self, job: Dict[str, Any]) -> str:
        """Format detailed job information (scontrol style).

        Args:
            job: Job dictionary

        Returns:
            Formatted job details
        """
        lines = []

        # Primary information
        lines.append(
            f"JobId={job.get('JOBID', 'unknown')} " f"JobName={job.get('NAME', 'unknown')}"
        )

        # State information
        lines.append(
            f"   JobState={job.get('STATE', 'UNKNOWN')} "
            f"Reason={job.get('REASON', 'None')} "
            f"Dependency={job.get('DEPENDENCY', 'None')}"
        )

        # Resource information
        lines.append(
            f"   NumNodes={job.get('NODES', 1)} "
            f"NumCPUs={job.get('CPUS', 1)} "
            f"NumTasks={job.get('NTASKS', 1)} "
            f"CPUs/Task={job.get('CPUS_PER_TASK', 1)}"
        )

        # Time information
        lines.append(
            f"   RunTime={job.get('TIME', '00:00:00')} "
            f"TimeLimit={job.get('TIME_LIMIT', 'UNLIMITED')} "
            f"TimeMin={job.get('TIME_MIN', 'N/A')}"
        )

        # Additional fields
        if "PARTITION" in job:
            lines.append(f"   Partition={job['PARTITION']}")

        if "QOS" in job:
            lines.append(f"   QOS={job['QOS']}")

        if "NODELIST" in job:
            lines.append(f"   NodeList={job['NODELIST']}")

        return "\\n".join(lines)
