"""Image utility for adding measurement rulers to screenshots.

This module provides a function to add horizontal and vertical rulers to an image,
useful for visual measurement and debugging in screenshot workflows.
"""

import sys
from dataclasses import dataclass
from PIL import Image, ImageDraw, ImageFont


@dataclass
class RulerSettings:  # pylint: disable=too-many-instance-attributes
    """Configuration for ruler appearance."""

    size: int = 30
    major_interval: int = 100
    mid_interval: int = 50
    minor_interval: int = 10
    major_length: int = 8
    mid_length: int = 6
    minor_length: int = 3
    color: str = "#555"
    bg_color: str = "#f0f0f0"


@dataclass
class TickInfo:
    """Information needed to draw a single tick."""

    pos: int
    length: int
    text: str = ""


def add_rulers(input_path: str, output_path: str = None) -> str:
    """Adds horizontal and vertical measurement rulers to an image.

    Args:
        input_path: Path to the input image.
        output_path: Path to save the output image. Defaults to input_path.

    Returns:
        The path to the saved output image.
    """
    settings = RulerSettings()
    output_path = output_path or input_path

    try:
        with Image.open(input_path) as orig_img:
            img = _create_base_image(orig_img, settings)
            draw = ImageDraw.Draw(img)
            fonts = _load_fonts()

            _draw_horizontal_ruler(orig_img.width, draw, fonts, settings)
            _draw_vertical_ruler(orig_img.height, draw, fonts, settings)

            img.save(output_path)
    except FileNotFoundError:
        print(f"Error: Input file not found at {input_path}")
        sys.exit(1)
    except IOError as e:
        print(f"Error processing image: {e}")
        sys.exit(1)

    return output_path


def _create_base_image(orig_img: Image.Image, settings: RulerSettings) -> Image.Image:
    """Creates a new image canvas with space for rulers and pastes the original."""
    new_width = orig_img.width + settings.size
    new_height = orig_img.height + settings.size
    img = Image.new("RGB", (new_width, new_height), settings.bg_color)
    img.paste(orig_img, (settings.size, settings.size))
    return img


def _load_fonts() -> tuple[ImageFont.FreeTypeFont, ImageFont.FreeTypeFont]:
    """Loads preferred fonts or falls back to default."""
    try:
        major_font = ImageFont.truetype("DejaVuSans.ttf", 10)
        mid_font = ImageFont.truetype("DejaVuSans.ttf", 8)
    except IOError:
        major_font = ImageFont.load_default()
        mid_font = major_font
    return major_font, mid_font


def _draw_horizontal_ruler(
    width: int, draw: ImageDraw.Draw, fonts: tuple, settings: RulerSettings
) -> None:
    """Draws the horizontal ruler with ticks and labels."""
    major_font, mid_font = fonts
    for x in range(0, width, settings.minor_interval):
        is_major = x % settings.major_interval == 0
        is_mid = x % settings.mid_interval == 0

        if is_major:
            tick_info = TickInfo(pos=x, length=settings.major_length, text=str(x))
            _draw_tick(draw, tick_info, major_font, settings, horizontal=True)
        elif is_mid:
            tick_info = TickInfo(pos=x, length=settings.mid_length, text=str(x))
            _draw_tick(draw, tick_info, mid_font, settings, horizontal=True)
        else:
            _draw_minor_tick(draw, x, settings.minor_length, settings, True)


def _draw_vertical_ruler(
    height: int, draw: ImageDraw.Draw, fonts: tuple, settings: RulerSettings
) -> None:
    """Draws the vertical ruler with ticks and labels."""
    major_font, mid_font = fonts
    for y in range(0, height, settings.minor_interval):
        is_major = y % settings.major_interval == 0
        is_mid = y % settings.mid_interval == 0

        if is_major:
            tick_info = TickInfo(pos=y, length=settings.major_length, text=str(y))
            _draw_tick(draw, tick_info, major_font, settings, horizontal=False)
        elif is_mid:
            tick_info = TickInfo(pos=y, length=settings.mid_length, text=str(y))
            _draw_tick(draw, tick_info, mid_font, settings, horizontal=False)
        else:
            _draw_minor_tick(draw, y, settings.minor_length, settings, False)


def _draw_tick(
    draw: ImageDraw.Draw,
    tick_info: TickInfo,
    font: ImageFont.FreeTypeFont,
    settings: RulerSettings,
    *,
    horizontal: bool,
) -> None:
    """Draws a major or mid tick mark with its label."""
    if horizontal:
        x = tick_info.pos + settings.size
        draw.line(
            (x, settings.size - tick_info.length, x, settings.size),
            fill=settings.color,
            width=1,
        )
        text_width = font.getlength(tick_info.text)
        draw.text(
            (x - text_width / 2, settings.size - tick_info.length - font.size - 2),
            tick_info.text,
            fill=settings.color,
            font=font,
        )
    else:
        y = tick_info.pos + settings.size
        draw.line(
            (settings.size - tick_info.length, y, settings.size, y),
            fill=settings.color,
            width=1,
        )
        text_width = font.getlength(tick_info.text)
        text_x = max(2, settings.size - tick_info.length - text_width - 2)
        draw.text(
            (text_x, y - font.size // 2), tick_info.text, fill=settings.color, font=font
        )


def _draw_minor_tick(
    draw: ImageDraw.Draw,
    pos: int,
    length: int,
    settings: RulerSettings,
    horizontal: bool,
) -> None:
    """Draws a minor tick mark."""
    if horizontal:
        x = pos + settings.size
        draw.line(
            (x, settings.size - length, x, settings.size), fill=settings.color, width=1
        )
    else:
        y = pos + settings.size
        draw.line(
            (settings.size - length, y, settings.size, y), fill=settings.color, width=1
        )


if __name__ == "__main__":
    if len(sys.argv) > 1:
        add_rulers(sys.argv[1])
    else:
        print("Usage: python add_rulers.py <input_image_path> [output_image_path]")
