/*
 * Deskflow -- mouse and keyboard sharing utility
 * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
 * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
 */

#pragma once

#include "deskflow/ClipboardTypes.h"
#include "deskflow/IClipboard.h"

#include <atomic>
#include <fcntl.h>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

#include <QObject>
#include <QString>

class QProcess;
//! Wayland clipboard implementation using wl-copy/wl-paste
/*!
This class implements clipboard functionality for Wayland environments
by using the wl-clipboard utilities (wl-copy and wl-paste).
*/
class WlClipboard : public QObject, public IClipboard
{
  Q_OBJECT
public:
  explicit WlClipboard(ClipboardID id);
  WlClipboard(WlClipboard const &) = delete;
  WlClipboard(WlClipboard &&) = delete;
  ~WlClipboard() override;

  WlClipboard &operator=(WlClipboard const &) = delete;
  WlClipboard &operator=(WlClipboard &&) = delete;

  //! Get clipboard ID
  ClipboardID getID() const;

  //! Check if wl-clipboard tools are available
  static bool isAvailable();

  //! Check if WlClipboard is enabled
  static bool isEnabled();

  //! Start monitoring clipboard changes
  void startMonitoring();

  //! Stop monitoring clipboard changes
  void stopMonitoring();

  //! Check if clipboard has changed
  bool hasChanged() const;

  //! Reset the changed flag and clear cache
  void resetChanged();

  // IClipboard overrides
  bool empty() override;
  void add(Format format, const std::string &data) override;
  bool open(Time time) const override;
  void close() const override;
  Time getTime() const override;
  bool has(Format format) const override;
  std::string get(Format format) const override;

private:
  //! Convert IClipboard format to MIME type
  QString formatToMimeType(Format format) const;

  //! Convert MIME type to IClipboard format
  Format mimeTypeToFormat(const QString &mimeType) const;

  //! Get available MIME types from clipboard
  QStringList getAvailableMimeTypes() const;

  //! Monitor clipboard changes in background thread
  void monitorClipboard();

  //! Get current clipboard serial/timestamp
  Time getCurrentTime() const;

  //! Check if we own the clipboard
  bool isOwned() const;

  //! Update our ownership status
  void updateOwnership(bool owned);

  //! Invalidate cached clipboard data
  void invalidateCache();

private:
  ClipboardID m_id;
  mutable bool m_open = false;
  mutable Time m_time = 0;
  mutable Time m_cachedTime = 0;
  mutable bool m_owned = false;
  mutable std::atomic<bool> m_hasChanged = false;

  // Cached clipboard data
  mutable std::mutex m_cacheMutex;
  mutable bool m_cached = false;
  mutable std::string m_cachedData[static_cast<int>(Format::TotalFormats)];
  mutable bool m_cachedAvailable[static_cast<int>(Format::TotalFormats)];

  // Background monitoring
  std::unique_ptr<std::thread> m_monitorThread;
  std::atomic<bool> m_monitoring = false;
  std::atomic<bool> m_stopMonitoring = false;

  // Clipboard selection type (true = clipboard, false = primary)
  bool m_useClipboard;

  // Hold a ref to running wl-copy processes
  QList<QProcess *> m_runningWlCopies;
};
