#pragma once

#include "generation.hpp"

#include <QList>
#include <QObject>
#include <QString>
#include <QtQml>

namespace ZShell::llm {

class ChatMessage : public QObject {
	Q_OBJECT
	QML_ELEMENT
	QML_UNCREATABLE("Chat messages are created by the Chat singleton")

	Q_PROPERTY(Role role READ role CONSTANT)
	Q_PROPERTY(qint64 timestamp READ timestamp CONSTANT)
	Q_PROPERTY(
		int generationCount READ generationCount NOTIFY generationsChanged)
	Q_PROPERTY(
		QList<ZShell::llm::ChatGeneration*> generations READ generations NOTIFY
			generationsChanged)
	Q_PROPERTY(
		ZShell::llm::ChatGeneration* activeGeneration READ activeGeneration
			NOTIFY activeGenerationChanged)
	Q_PROPERTY(
		int activeGenerationIndex READ activeGenerationIndex NOTIFY
			activeGenerationChanged)

	public:
	enum class Role : int { User = 0, Assistant };
	Q_ENUM(Role)

	explicit ChatMessage(Role role, qint64 timestamp, QObject* parent = nullptr);

	[[nodiscard]] Role role() const { return m_role; }
	[[nodiscard]] qint64 timestamp() const { return m_timestamp; }
	[[nodiscard]] int generationCount() const {
		return static_cast<int>(m_generations.size());
	}
	[[nodiscard]] QList<ChatGeneration*> generations() const {
		return m_generations;
	}
	[[nodiscard]] ChatGeneration* activeGeneration() const {
		return generation(m_active);
	}
	[[nodiscard]] int activeGenerationIndex() const { return m_active; }
	[[nodiscard]] ChatGeneration* generation(int index) const {
		if (index < 0 || index >= m_generations.size()) return nullptr;
		return m_generations.at(index);
	}

	Q_INVOKABLE void setActiveGeneration(int index);
	Q_INVOKABLE void edit(const QString& newContent);
	Q_INVOKABLE void retry();
	Q_INVOKABLE void generate();

	ChatGeneration* addGeneration(qint64 timestamp);
	ChatGeneration* appendGeneration(qint64 timestamp);
	void removeGeneration(ChatGeneration* generation);

	Q_SIGNALS:
	void generationsChanged();
	void activeGenerationChanged();

	private:
	void setActiveInternal(int index);

	Role m_role;
	qint64 m_timestamp;
	QList<ChatGeneration*> m_generations;
	int m_active = -1;
};

} // namespace ZShell::llm
