"""Validation for cheatly sheets - ensures content fits panel dimensions."""

from pathlib import Path
from typing import Sequence

from rich.console import Console
from rich.table import Table

from .config import Config
from .models import ValidationResult, PanelSpec, CodeSection
from .parser import SheetParser

from termcards import sheets
from termcards.sheets import SheetType


class Validator:
    """Validates sheet files for proper dimensions."""

    def __init__(self, parser: SheetParser | None = None) -> None:
        """Initialize the validator.

        Args:
            parser: Optional custom parser instance to use for parsing sheets.
                   If None, creates a new SheetParser instance.
        """
        self.parser = parser or SheetParser()
        self.console = Console()

    def validate_paths(self, paths: Sequence[str | Path]) -> bool:
        """
        Validate files or directories.

        Args:
            paths: List of paths to validate (str or Path objects)

        Returns:
            True if all sheets are valid
        """
        results = []

        for path in paths:
            path = Path(path)

            if not path.exists():
                self.console.print(f"[red]Path not found: {path}[/red]")
                continue

            if path.is_dir():
                sheet_types: list[SheetType] = ["reference", "code"]
                for sheet_type in sheet_types:
                    for sheet_path in sheets.list_sheets(sheet_type):
                        results.extend(self._validate_file(sheet_path, sheet_type))
            else:
                sheet_type = sheets.get_sheet_type(path)
                results.extend(self._validate_file(path, sheet_type))

        return self._report(results)

    def _validate_file(
        self, path: Path, sheet_type: str = "reference"
    ) -> list[ValidationResult]:
        """Validate a single file.

        Args:
            path: Path to file to validate
            sheet_type: Type of sheet ("reference" or "code")

        Returns:
            List of validation results for each section
        """
        sheet = self.parser.parse(path, sheet_type)

        if not sheet:
            return [
                ValidationResult(
                    file=str(path),
                    section="ERROR",
                    max_width=0,
                    line_count=0,
                    valid=False,
                    message="Failed to parse file",
                )
            ]

        results = []
        for i, section in enumerate(sheet.sections):
            if isinstance(section, PanelSpec):
                result = self._check_panel(path, section)
            elif isinstance(section, CodeSection):
                result = self._check_code_section(path, section)
            else:
                result = ValidationResult(
                    file=str(path.name),
                    section=f"Unknown section type {i}",
                    max_width=0,
                    line_count=0,
                    valid=False,
                    message="Unknown section type",
                )
            results.append(result)

        return results

    def _check_panel(self, path: Path, section: PanelSpec) -> ValidationResult:
        """Check if a section's content fits its dimensions.

        Args:
            path: File path
            section: Section to validate

        Returns:
            Validation result
        """
        layout = Config.LAYOUT
        max_width = layout.usable_width

        # Use the effective_max_items property which handles multi-line layout
        max_height = section.effective_max_items
        line_count = len(section.items)
        actual_width = 0
        problem_lines = []

        for i, item in enumerate(section.items):
            if isinstance(item, dict):
                if "cmd" in item:
                    # Multi-line layout: only check command width
                    cmd = item.get("cmd", "")
                    cmd_width = len(cmd)
                    if cmd_width > actual_width:
                        actual_width = cmd_width
                    if cmd_width > max_width:
                        problem_lines.append(
                            f"Line {i + 1}: command '{cmd}' = {cmd_width} chars"
                        )
                elif "key" in item:
                    # Single-line layout: check combined width
                    key = item.get("key", "")
                    desc = item.get("desc", "")
                    line_width = len(key) + layout.min_key_desc_gap + len(desc)
                    if line_width > actual_width:
                        actual_width = line_width
                    if line_width > max_width:
                        problem_lines.append(
                            f"Line {i + 1}: '{key}' + '{desc}' = {line_width} chars"
                        )

        valid = True
        messages = []

        if line_count > max_height:
            valid = False
            messages.append(f"Too many items: {line_count} (max {max_height})")

        if problem_lines:
            valid = False
            messages.append(f"Lines too long (max {max_width}):")
            messages.extend(f"  {line}" for line in problem_lines[:3])
            if len(problem_lines) > 3:
                messages.append(f"  ... and {len(problem_lines) - 3} more")

        message = "\n".join(messages) if messages else None

        return ValidationResult(
            file=str(path.name),
            section=section.title,
            max_width=actual_width,
            line_count=line_count,
            valid=valid,
            message=message,
        )

    def _check_code_section(self, path: Path, section: CodeSection) -> ValidationResult:
        """Check if a code section meets constraints from Config.

        Args:
            path: File path
            section: Code section to validate

        Returns:
            Validation result
        """
        code_layout = Config.CODE_LAYOUT
        max_lines = code_layout.get_max_lines(section.size)
        max_line_width = code_layout.max_line_width

        line_count = section.line_count
        lines = section.code.splitlines()
        max_width = max(len(line) for line in lines) if lines else 0

        valid = True
        messages = []

        if line_count > max_lines:
            valid = False
            messages.append(
                f"Too many lines: {line_count} (max {max_lines} for {section.size})"
            )

        if max_width > max_line_width:
            valid = False
            messages.append(f"Lines too wide: {max_width} chars (max {max_line_width})")

        message = "\n".join(messages) if messages else None

        return ValidationResult(
            file=str(path.name),
            section=section.title,
            max_width=max_width,
            line_count=line_count,
            valid=valid,
            message=message,
        )

    def _report(self, results: list[ValidationResult]) -> bool:
        """Print validation report."""
        if not results:
            self.console.print("[yellow]No sheets found to validate[/yellow]")
            return True

        table = Table(title="Sheet Validation Results")
        table.add_column("File")
        table.add_column("Section")
        table.add_column("Size", justify="right")
        table.add_column("Status", justify="center")
        table.add_column("Message")

        all_valid = True
        for result in results:
            size = f"{result.max_width}×{result.line_count}"
            status = "✓" if result.valid else "✗"

            if not result.valid:
                all_valid = False

            table.add_row(
                result.file, result.section, size, status, result.message or ""
            )

        self.console.print(table)

        valid_count = sum(1 for r in results if r.valid)
        total_count = len(results)

        if all_valid:
            self.console.print(f"\n[green]✓ All {total_count} panels valid[/green]")
        else:
            self.console.print(f"\n[red]{valid_count}/{total_count} panels valid[/red]")

        return all_valid
