#pragma once
#include <algorithm>
#include <random>
#include <span>
#include <string_view>
#include <vector>
#include <QBrush>
#include <QByteArray>
#include <QColor>
#include <QPen>
#include <QString>
#include <QTime>
#include "render_2D/export.h"
#include "Qt/plot/export.h"
#include "Widget/export.h"
namespace renderive {
template <typename T>
using Node = Flex_Qt::Node<T>;
template <typename T>
using Node_Manager = Flex_Qt::Node_Manager<T>;
template <typename T>
using Roll_Object = Flex_Qt::Roll_Object<T>;
template <typename T>
using Singleton_Widget = Flex_Qt::Singleton_Widget<T>;
using Select_Color_Dialog = Flex_Qt::Select_Color_Dialog;
using Virtual_Keyboard = Flex_Qt::Virtual_Keyboard;
inline Color qt_to_color(const QColor& color) {
    if (!color.isValid())
        return Color::transparent();
    return {
        static_cast<std::uint8_t>(color.red()),
        static_cast<std::uint8_t>(color.green()),
        static_cast<std::uint8_t>(color.blue()),
        static_cast<std::uint8_t>(color.alpha())
    };
}
inline QColor to_qcolor(Color color) {
    return QColor(color.r, color.g, color.b, color.a);
}
inline Line_Style qt_to_line_style(Qt::PenStyle style) {
    switch (style) {
    case Qt::NoPen:
        return Line_Style::None;
    case Qt::DashLine:
    case Qt::DashDotLine:
    case Qt::DashDotDotLine:
        return Line_Style::Dash;
    case Qt::DotLine:
        return Line_Style::Dot;
    default:
        return Line_Style::Solid;
    }
}
inline Line_Cap qt_to_line_cap(Qt::PenCapStyle cap) {
    switch (cap) {
    case Qt::SquareCap:
        return Line_Cap::Square;
    case Qt::RoundCap:
        return Line_Cap::Round;
    case Qt::FlatCap:
    default:
        return Line_Cap::Butt;
    }
}
inline Qt::PenCapStyle to_qt_line_cap(Line_Cap cap) {
    switch (cap) {
    case Line_Cap::Square:
        return Qt::SquareCap;
    case Line_Cap::Round:
        return Qt::RoundCap;
    case Line_Cap::Butt:
    default:
        return Qt::FlatCap;
    }
}
inline Line_Join qt_to_line_join(Qt::PenJoinStyle join) {
    switch (join) {
    case Qt::BevelJoin:
        return Line_Join::Bevel;
    case Qt::RoundJoin:
        return Line_Join::Round;
    case Qt::MiterJoin:
    case Qt::SvgMiterJoin:
    default:
        return Line_Join::Miter;
    }
}
inline Qt::PenJoinStyle to_qt_line_join(Line_Join join) {
    switch (join) {
    case Line_Join::Bevel:
        return Qt::BevelJoin;
    case Line_Join::Round:
        return Qt::RoundJoin;
    case Line_Join::Miter:
    default:
        return Qt::MiterJoin;
    }
}
inline Qt::PenStyle to_qt_pen_style(Line_Style style) {
    switch (style) {
    case Line_Style::None:
        return Qt::NoPen;
    case Line_Style::Dash:
        return Qt::DashLine;
    case Line_Style::Dot:
        return Qt::DotLine;
    default:
        return Qt::SolidLine;
    }
}
inline Pen qt_to_pen(const QPen& pen) {
    return Pen{
        qt_to_color(pen.color()), pen.widthF(), qt_to_line_style(pen.style()),
        qt_to_line_cap(pen.capStyle()), qt_to_line_join(pen.joinStyle())
    };
}
inline Pen qt_to_pen(const QColor& color) {
    if (!color.isValid())
        return Pen{.style = Line_Style::None};
    return Pen{qt_to_color(color)};
}
inline QPen to_qpen(const Pen& pen) {
    QPen ret(to_qcolor(pen.color));
    ret.setWidthF(pen.width);
    ret.setStyle(to_qt_pen_style(pen.style));
    ret.setCapStyle(to_qt_line_cap(pen.cap));
    ret.setJoinStyle(to_qt_line_join(pen.join));
    return ret;
}
inline Brush qt_to_brush(const QBrush& brush) {
    if (brush.style() == Qt::NoBrush)
        return Brush{};
    return Brush{qt_to_color(brush.color()), Brush_Style::Solid};
}
inline Brush qt_to_brush(const QColor& color) {
    if (!color.isValid())
        return Brush{};
    return Brush{qt_to_color(color), Brush_Style::Solid};
}
inline QBrush to_qbrush(const Brush& brush) {
    if (!brush.enabled())
        return QBrush(Qt::NoBrush);
    return QBrush(to_qcolor(brush.color));
}
inline std::string qt_to_string(const QString& text) {
    QByteArray bytes = text.toUtf8();
    return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));
}
inline QString to_qstring(std::string_view text) {
    return QString::fromUtf8(text.data(), static_cast<int>(text.size()));
}
inline Orientation qt_to_orientation(Qt::Orientation orientation) {
    return orientation == Qt::Horizontal ? Orientation::Horizontal : Orientation::Vertical;
}
inline Qt::Orientation to_qt_orientation(Orientation orientation) {
    return orientation == Orientation::Horizontal ? Qt::Horizontal : Qt::Vertical;
}
inline Time_Of_Day qt_to_time_of_day(const QTime& time) {
    return {time.isValid() ? time.msecsSinceStartOfDay() : -1};
}
namespace detail {
inline std::default_random_engine& mock_data_random_engine() {
    static thread_local std::default_random_engine engine(std::random_device{}());
    return engine;
}
} // namespace detail
inline void fill_data(Range value_range, std::span<double> output) {
    if (value_range.origin > value_range.target)
        std::swap(value_range.origin, value_range.target);
    std::uniform_real_distribution<double> dist(value_range.origin, value_range.target);
    for (double& value : output)
        value = dist(detail::mock_data_random_engine());
}
inline std::vector<double> get_data(Range value_range, int size) {
    std::vector<double> ret(static_cast<std::size_t>(std::max(0, size)));
    fill_data(value_range, ret);
    return ret;
}
inline double get_data(Range value_range) {
    if (value_range.origin > value_range.target)
        std::swap(value_range.origin, value_range.target);
    std::uniform_real_distribution<double> dist(value_range.origin, value_range.target);
    return dist(detail::mock_data_random_engine());
}
inline std::vector<double> get_data(int value, int size) {
    return std::vector<double>(size, value);
}
inline std::vector<double> get_colored_data(int size) {
    std::vector<double> ret(size);
    for (int i = 0; i < size; ++i)
        ret[i] = i;
    return ret;
}
} // namespace renderive
