#pragma once

#include <QObject>
#include <QString>
#include <QStringList>
#include <QtQml>

#include "chatstore.hpp"

class QQmlEngine;
class QJSEngine;

namespace ZShell::llm {

class LlmClient;

// QML-facing facade. Persistence lives in ChatStore, network streaming in
// LlmClient; this class only wires them together and exposes the
// application-wide state.
class Chat : public QObject {
	Q_OBJECT
	QML_ELEMENT
	QML_SINGLETON

	Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
	Q_PROPERTY(QString endpoint READ endpoint NOTIFY endpointChanged)
	Q_PROPERTY(QString model READ model NOTIFY modelChanged)
	Q_PROPERTY(
		QStringList availableModels READ availableModels NOTIFY
			availableModelsChanged)
	Q_PROPERTY(int contextSize READ contextSize NOTIFY contextSizeChanged)
	Q_PROPERTY(
		bool toolsEnabled READ toolsEnabled WRITE setToolsEnabled NOTIFY
			toolsEnabledChanged)
	Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
	Q_PROPERTY(ZShell::llm::ChatStore* chats READ chats CONSTANT)
	Q_PROPERTY(
		QString streamingChatId READ streamingChatId NOTIFY
			streamingChatIdChanged)

	public:
	explicit Chat(QObject* parent = nullptr);

	[[nodiscard]] bool busy() const;
	[[nodiscard]] QString endpoint() const;
	[[nodiscard]] QString model() const;
	[[nodiscard]] QStringList availableModels() const;
	[[nodiscard]] int contextSize() const;
	[[nodiscard]] bool toolsEnabled() const;
	void setToolsEnabled(bool value);
	[[nodiscard]] QString lastError() const { return m_lastError; }
	[[nodiscard]] ChatStore* chats() const { return m_store; }
	[[nodiscard]] QString streamingChatId() const;

	Q_INVOKABLE void stop();
	Q_INVOKABLE void dismissError();
	Q_INVOKABLE void refreshModels();
	Q_INVOKABLE void selectModel(const QString& id);

	static Chat* create(QQmlEngine*, QJSEngine*);

	Q_SIGNALS:
	void busyChanged();
	void endpointChanged();
	void modelChanged();
	void availableModelsChanged();
	void contextSizeChanged();
	void toolsEnabledChanged();
	void errorOccurred(const QString& message);
	void lastErrorChanged();
	void streamingChatIdChanged();

	private:
	ChatStore* m_store = nullptr;
	LlmClient* m_client = nullptr;
	QString m_lastError;

	static Chat* s_instance;
};

} // namespace ZShell::llm
