from typing import TYPE_CHECKING

from .common import (
    COLOUR_BLACK,
    COLOUR_WHITE,
    TEXT_ELLIPSIS,
    FontType,
    RenderMetrics,
    fit_text_to_width,
    measure_text,
)

if TYPE_CHECKING:
    from datetime import datetime

    from PIL import ImageDraw

BATTERY_TERMINAL_DIMENSION_MIN = 2
BATTERY_TERMINAL_WIDTH_DIVISOR = 12
BATTERY_TERMINAL_HEIGHT_DIVISOR = 2
BATTERY_INNER_PADDING_MIN = 2


def build_weather_stale_message(stale_hours: int | None) -> str:
    display_hours = stale_hours if stale_hours is not None else 1
    units = "hour" if display_hours == 1 else "hours"
    return f"Warning: weather data is {display_hours} {units} stale"


def draw_battery_icon(
    draw: ImageDraw.ImageDraw,
    x: int,
    y: int,
    width: int,
    height: int,
    outline_width: int,
    battery_level: int,
) -> None:
    terminal_width = max(
        BATTERY_TERMINAL_DIMENSION_MIN,
        width // BATTERY_TERMINAL_WIDTH_DIVISOR,
    )
    body_right = x + width - terminal_width - 1
    body_bottom = y + height - 1

    draw.rectangle(
        (x, y, body_right, body_bottom),
        outline=COLOUR_BLACK,
        width=outline_width,
        fill=COLOUR_WHITE,
    )

    terminal_height = max(
        BATTERY_TERMINAL_DIMENSION_MIN,
        height // BATTERY_TERMINAL_HEIGHT_DIVISOR,
    )
    terminal_top = y + (height - terminal_height) // 2
    draw.rectangle(
        (
            body_right + 1,
            terminal_top,
            x + width - 1,
            terminal_top + terminal_height - 1,
        ),
        outline=COLOUR_BLACK,
        fill=COLOUR_BLACK,
    )

    inner_padding = max(BATTERY_INNER_PADDING_MIN, outline_width + 1)
    inner_left = x + inner_padding
    inner_top = y + inner_padding
    inner_right = body_right - inner_padding
    inner_bottom = body_bottom - inner_padding
    if inner_left > inner_right or inner_top > inner_bottom:
        return

    inner_width = inner_right - inner_left + 1
    fill_width = round(inner_width * (battery_level / 100))
    if fill_width <= 0:
        return

    draw.rectangle(
        (inner_left, inner_top, inner_left + fill_width - 1, inner_bottom),
        fill=COLOUR_BLACK,
    )


def draw_header(
    draw: ImageDraw.ImageDraw,
    font: FontType,
    scaled_width: int,
    now: datetime,
    *,
    battery_level: int | None,
    weather_data_stale: bool,
    weather_data_stale_hours: int | None,
    weather_status_message: str | None,
    metrics: RenderMetrics,
) -> tuple[int, int]:
    top_y = metrics.border_width + metrics.padding
    left_edge = metrics.border_width + metrics.padding
    right_edge = scaled_width - left_edge

    clock_label = now.strftime("%H:%M")
    clock_text_width, clock_text_height, _ = measure_text(draw, font, clock_label)
    clock_x = max(left_edge, right_edge - clock_text_width)
    header_bottom = top_y + clock_text_height

    if battery_level is not None:
        battery_label = f"{battery_level}%"
        (
            battery_text_width,
            battery_text_height,
            battery_text_top_offset,
        ) = measure_text(draw, font, battery_label)
        battery_icon_height = max(
            metrics.battery_icon_min_height,
            battery_text_height + metrics.battery_icon_text_padding,
        )
        battery_icon_width = battery_icon_height * 2
        right_group_width = (
            battery_text_width
            + metrics.group_spacing
            + battery_icon_width
            + metrics.group_spacing
            + clock_text_width
        )
        battery_text_x = max(left_edge, right_edge - right_group_width)
        battery_icon_x = battery_text_x + battery_text_width + metrics.group_spacing
        battery_icon_y = (
            top_y
            + battery_text_top_offset
            + (battery_text_height - battery_icon_height) // 2
        )
        clock_x = battery_icon_x + battery_icon_width + metrics.group_spacing

        draw.text((battery_text_x, top_y), battery_label, fill=COLOUR_BLACK, font=font)
        draw_battery_icon(
            draw=draw,
            x=battery_icon_x,
            y=battery_icon_y,
            width=battery_icon_width,
            height=battery_icon_height,
            outline_width=metrics.thin_shape_stroke_width,
            battery_level=battery_level,
        )
        header_bottom = max(header_bottom, battery_icon_y + battery_icon_height)

    draw.text((clock_x, top_y), clock_label, fill=COLOUR_BLACK, font=font)

    header_left_message: str | None = None
    if weather_data_stale:
        header_left_message = build_weather_stale_message(weather_data_stale_hours)
    elif weather_status_message:
        header_left_message = weather_status_message

    if header_left_message:
        warning_max_width = max(0, clock_x - left_edge - metrics.group_spacing)
        warning_text = fit_text_to_width(
            draw,
            font,
            header_left_message,
            warning_max_width,
            suffix=TEXT_ELLIPSIS,
        )
        if warning_text:
            if warning_text != header_left_message:
                warning_text = f"{warning_text}{TEXT_ELLIPSIS}"
            _, warning_height, _ = measure_text(draw, font, warning_text)
            draw.text((left_edge, top_y), warning_text, fill=COLOUR_BLACK, font=font)
            header_bottom = max(header_bottom, top_y + warning_height)

    return top_y, header_bottom
