from __future__ import annotations

from dataclasses import dataclass
import math

from .canvas import Box, RenderableComponent, SheetCanvas


@dataclass(frozen=True)
class GridConfig:
    tracks: int = 12
    start_col: int = 1
    end_col: int = 24


class Grid12:
    def __init__(self, canvas: SheetCanvas, config: GridConfig | None = None) -> None:
        self.canvas = canvas
        self.config = config or GridConfig()

        if self.config.tracks != 12:
            raise ValueError("Grid12 requires exactly 12 tracks")
        if self.config.end_col < self.config.start_col:
            raise ValueError("GridConfig end_col must be >= start_col")

    @property
    def _total_columns(self) -> int:
        return self.config.end_col - self.config.start_col + 1

    def _track_to_col_start(self, x: int) -> int:
        return self.config.start_col + math.floor((x - 1) * self._total_columns / self.config.tracks)

    def _track_to_col_end(self, x_end: int) -> int:
        return self.config.start_col + math.ceil(x_end * self._total_columns / self.config.tracks) - 1

    def put(
        self,
        component: RenderableComponent,
        y: int,
        x: int,
        w: int,
        h: int,
    ) -> Box:
        if y <= 0:
            raise ValueError("Grid y must be >= 1")
        if x < 1 or x > self.config.tracks:
            raise ValueError("Grid x must be in [1, 12]")
        if w <= 0 or h <= 0:
            raise ValueError("Grid width/height must be > 0")

        x_end = x + w - 1
        if x_end > self.config.tracks:
            raise ValueError("Grid placement exceeds 12 columns")

        col_start = self._track_to_col_start(x)
        col_end = self._track_to_col_end(x_end)
        span_cols = col_end - col_start + 1

        return self.canvas.put(
            component=component,
            row=y,
            col=col_start,
            span_rows=h,
            span_cols=span_cols,
        )
