// SPDX-License-Identifier: MIT
// Geometric primitives.
// Copyright (C) 2026 Artem Senichev <artemsen@gmail.com>

#include "geometry.hpp"

#include <algorithm>

Point Point::operator+(const Point& delta) const
{
    return { .x = x + delta.x, .y = y + delta.y };
}

Point Point::operator-(const Point& other) const
{
    return { .x = x - other.x, .y = y - other.y };
}

Size Size::operator*(double factor) const
{
    if (factor <= 0.0) {
        return {};
    }
    return { .width = static_cast<size_t>(factor * width),
             .height = static_cast<size_t>(factor * height) };
}

Rectangle::Rectangle(const ssize_t x, const ssize_t y, const size_t width,
                     const size_t height)
    : x(x)
    , y(y)
    , width(width)
    , height(height)
{
}

Rectangle::Rectangle(const Point& pos, const Size& size)
    : x(pos.x)
    , y(pos.y)
    , width(size.width)
    , height(size.height)
{
}

Rectangle Rectangle::intersect(const Rectangle& other) const
{
    const ssize_t x1 = std::max(x, other.x);
    const ssize_t y1 = std::max(y, other.y);
    const ssize_t x2 = std::min(x + static_cast<ssize_t>(width),
                                other.x + static_cast<ssize_t>(other.width));
    const ssize_t y2 = std::min(y + static_cast<ssize_t>(height),
                                other.y + static_cast<ssize_t>(other.height));

    if (x2 <= x1 || y2 <= y1) {
        return {};
    }
    return { x1, y1, static_cast<size_t>(x2 - x1),
             static_cast<size_t>(y2 - y1) };
}

std::tuple<Rectangle, Rectangle, Rectangle, Rectangle>
Rectangle::cutout(const Rectangle& cut) const
{
    Rectangle top;
    Rectangle bottom;
    Rectangle left;
    Rectangle right;

    // top
    if (cut.y > y) {
        top.x = x;
        top.y = y;
        top.height = cut.y - y;
        top.width = width;
    }

    // bottom
    if (y + cut.y + static_cast<ssize_t>(cut.height) <
        y + static_cast<ssize_t>(height)) {
        bottom.x = x;
        bottom.y = cut.y + cut.height;
        bottom.width = width;
        bottom.height = (y + height) - bottom.y;
    }

    // left
    if (cut.x > x) {
        left.x = x;
        left.y = cut.y;
        left.width = cut.x - x;
        left.height = cut.height;
    }

    // right
    if (x + cut.x + static_cast<ssize_t>(cut.width) <
        x + static_cast<ssize_t>(width)) {
        right.x = cut.x + cut.width;
        right.y = cut.y;
        right.width = (x + width) - cut.x - cut.width;
        right.height = cut.height;
    }

    return std::make_tuple(top, bottom, left, right);
}
