import QtQuick
import Quickshell
import qs.Commons
import qs.Services.Keyboard
import qs.Services.Noctalia

Item {
  id: root

  // Provider metadata
  property string name: I18n.tr("launcher.providers.clipboard")
  property var launcher: null
  property string iconMode: Settings.data.appLauncher.iconMode
  property string supportedLayouts: "list" // List view for clipboard content
  property bool wrapNavigation: false // Don't wrap at end of list

  // Provider capabilities
  property bool handleSearch: false // Don't handle regular search

  // Preview support
  property bool hasPreview: Settings.data.appLauncher.enableClipPreview
  property string previewComponentPath: "./ClipboardPreview.qml"

  // Image handling - expose revision for reactive updates in delegates
  readonly property int imageRevision: ClipboardService.revision

  // Categories
  property var availableCategories: Settings.data.appLauncher.enableClipboardChips ? ["All", "Images", "Links", "Files", "Code", "Colors"] : []
  property string selectedCategory: "All"

  function selectCategory(cat) {
    if (selectedCategory !== cat) {
      selectedCategory = cat;
      if (launcher) {
        launcher.updateResults();
      }
    }
  }

  property var categoryIcons: {
    "All": iconMode === "tabler" ? "border-all" : "view-grid",
    "Images": iconMode === "tabler" ? "photo" : "image",
    "Links": iconMode === "tabler" ? "link" : "insert-link",
    "Files": iconMode === "tabler" ? "file" : "text-x-generic",
    "Code": iconMode === "tabler" ? "code" : "text-x-script",
    "Colors": iconMode === "tabler" ? "palette" : "color-picker"
  }

  // Internal state
  property bool isWaitingForData: false
  property bool gotResults: false
  property string lastSearchText: ""

  // Listen for clipboard data updates
  Connections {
    target: ClipboardService
    function onListCompleted() {
      if (gotResults && (lastSearchText === searchText)) {
        // Do not update results after the first fetch.
        // This will avoid the list resetting every 2seconds when the service updates.
        return;
      }
      // Refresh results if we're waiting for data or if clipboard plugin is active
      if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
        isWaitingForData = false;
        gotResults = true;
        if (launcher) {
          launcher.updateResults();
        }
      }
    }
    function onActiveChanged() {
      // When active state changes (e.g. dependency check completes), refresh results
      if (ClipboardService.active && launcher && launcher.searchText.startsWith(">clip")) {
        isWaitingForData = true;
        gotResults = false;
        ClipboardService.list(100);
      }
    }
  }

  // Initialize provider
  function init() {
    Logger.d("ClipboardProvider", "Initialized");
    // Pre-load clipboard data if service is active
    if (ClipboardService.active) {
      ClipboardService.list(100);
    }
  }

  // Called when launcher opens
  function onOpened() {
    isWaitingForData = true;
    gotResults = false;
    lastSearchText = "";

    // Refresh clipboard history when launcher opens
    if (ClipboardService.active) {
      ClipboardService.list(100);
    }
  }

  // Check if this provider handles the command
  function handleCommand(searchText) {
    return searchText.startsWith(">clip");
  }

  // Return available commands when user types ">"
  function commands() {
    return [
          {
            "name": ">clip",
            "description": I18n.tr("launcher.providers.clipboard-search-description"),
            "icon": iconMode === "tabler" ? "clipboard" : "diodon",
            "isTablerIcon": true,
            "isImage": false,
            "onActivate": function () {
              launcher.setSearchText(">clip ");
            }
          },
          {
            "name": ">clip clear",
            "description": I18n.tr("launcher.providers.clipboard-clear-description"),
            "icon": iconMode === "tabler" ? "trash" : "user-trash",
            "isTablerIcon": true,
            "isImage": false,
            "onActivate": function () {
              ClipboardService.wipeAll();
              launcher.close();
            }
          }
        ];
  }

  // Get search results
  function getResults(searchText) {
    if (!searchText.startsWith(">clip")) {
      return [];
    }

    lastSearchText = searchText;
    const results = [];
    const query = searchText.slice(5).trim();

    // Check if clipboard service is not active
    if (!ClipboardService.active) {
      // If dependency check hasn't completed yet, show loading instead of disabled
      if (!ClipboardService.dependencyChecked) {
        return [
              {
                "name": I18n.tr("launcher.providers.clipboard-loading"),
                "description": I18n.tr("launcher.providers.emoji-loading-description"),
                "icon": iconMode === "tabler" ? "refresh" : "view-refresh",
                "isTablerIcon": true,
                "isImage": false,
                "onActivate": function () {}
              }
            ];
      }
      return [
            {
              "name": I18n.tr("launcher.providers.clipboard-history-disabled"),
              "description": I18n.tr("launcher.providers.clipboard-history-disabled-description"),
              "icon": iconMode === "tabler" ? "refresh" : "view-refresh",
              "isTablerIcon": true,
              "isImage": false,
              "onActivate": function () {}
            }
          ];
    }

    // Special command: clear
    if (query === "clear") {
      return [
            {
              "name": I18n.tr("launcher.providers.clipboard-clear-history"),
              "description": I18n.tr("launcher.providers.clipboard-clear-description-full"),
              "icon": iconMode === "tabler" ? "trash" : "user-trash",
              "isTablerIcon": true,
              "isImage": false,
              "onActivate": function () {
                ClipboardService.wipeAll();
                launcher.close();
              }
            }
          ];
    }

    // Show loading state if data is being loaded
    if (ClipboardService.loading || isWaitingForData) {
      return [
            {
              "name": I18n.tr("launcher.providers.clipboard-loading"),
              "description": I18n.tr("launcher.providers.emoji-loading-description"),
              "icon": iconMode === "tabler" ? "refresh" : "view-refresh",
              "isTablerIcon": true,
              "isImage": false,
              "onActivate": function () {}
            }
          ];
    }

    // Get clipboard items
    const items = ClipboardService.items || [];

    // If no items and we haven't tried loading yet, trigger a load
    if (items.count === 0 && !ClipboardService.loading) {
      isWaitingForData = true;
      ClipboardService.list(100);
      return [
            {
              "name": I18n.tr("launcher.providers.clipboard-loading"),
              "description": I18n.tr("launcher.providers.emoji-loading-description"),
              "icon": iconMode === "tabler" ? "refresh" : "view-refresh",
              "isTablerIcon": true,
              "isImage": false,
              "onActivate": function () {}
            }
          ];
    }

    // Search clipboard items
    const searchTerm = query.toLowerCase();

    const now = Date.now() / 1000;

    const catMap = {
      "Images": "image",
      "Links": "link",
      "Files": "file",
      "Code": "code",
      "Colors": "color"
    };

    // Filter and format results
    items.forEach(function (item) {
      // Category filter
      if (Settings.data.appLauncher.enableClipboardChips && root.selectedCategory !== "All") {
        if (item.contentType !== catMap[root.selectedCategory]) {
          return;
        }
      }

      const preview = (item.preview || "").toLowerCase();

      // Skip if search term doesn't match
      if (searchTerm && preview.indexOf(searchTerm) === -1) {
        return;
      }

      const firstSeen = ClipboardService.firstSeenById[item.id] || now;

      // Format the result based on type
      let entry;
      if (item.isImage) {
        entry = formatImageEntry(item, firstSeen);
      } else {
        entry = formatTextEntry(item, firstSeen);
      }

      // Add activation handler
      entry.onActivate = function () {
        if (Settings.data.appLauncher.autoPasteClipboard) {
          launcher.closeImmediately();
          Qt.callLater(() => {
                         ClipboardService.pasteFromClipboard(item.id, item.mime);
                       });
        } else {
          ClipboardService.copyToClipboard(item.id);
          launcher.close();
        }
      };

      results.push(entry);
    });

    // Show empty state if no results
    if (results.length === 0) {
      results.push({
                     "name": searchTerm ? "No matching clipboard items" : "Clipboard is empty",
                     "description": searchTerm ? `No items containing "${query}"` : "Copy something to see it here",
                     "icon": iconMode === "tabler" ? "clipboard" : "text-x-generic",
                     "isTablerIcon": true,
                     "isImage": false,
                     "onActivate": function () {// Do nothing
                     }
                   });
    }

    //Logger.i("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
    return results;
  }

  function formatImageEntry(item, firstSeen) {
    const meta = ClipboardService.parseImageMeta(item.preview);
    const timeStr = Time.formatRelativeTime(new Date(firstSeen * 1000));
    let desc = meta ? `${meta.fmt} • ${meta.size}` : item.mime || "Image data";
    if (timeStr)
      desc += ` • ${timeStr}`;

    return {
      "name": meta ? `Image ${meta.w}×${meta.h}` : "Image",
      "description": desc,
      "icon": iconMode === "tabler" ? "photo" : "image",
      "isTablerIcon": true,
      "isImage": true,
      "imageWidth": meta ? meta.w : 0,
      "imageHeight": meta ? meta.h : 0,
      "clipboardId": item.id,
      "mime": item.mime,
      "preview": item.preview,
      "provider": root
    };
  }

  function formatTextEntry(item, firstSeen) {
    const preview = (item.preview || "").trim();
    const lines = preview.split('\n').filter(l => l.trim());

    let title = lines[0] || "Empty text";
    if (title.length > 60) {
      title = title.substring(0, 57) + "...";
    }

    let description = "";
    if (lines.length > 1) {
      description = lines[1];
      if (description.length > 80) {
        description = description.substring(0, 77) + "...";
      }
    } else {
      // Preview is truncated at ~100 chars, so we can't show exact count
      if (preview.length >= 100) {
        description = I18n.tr("toast.clipboard.long-text");
      } else {
        const chars = preview.length;
        const words = preview.split(/\s+/).length;
        description = `${chars} characters, ${words} word${words !== 1 ? 's' : ''}`;
      }
    }

    const timeStr = Time.formatRelativeTime(new Date(firstSeen * 1000));
    if (timeStr)
      description += ` • ${timeStr}`;

    let defaultIcon = iconMode === "tabler" ? "clipboard" : "text-x-generic";
    let colorHex = "";
    if (Settings.data.appLauncher.enableClipboardSmartIcons) {
      if (item.contentType === "link")
        defaultIcon = iconMode === "tabler" ? "link" : "insert-link";
      else if (item.contentType === "file")
        defaultIcon = iconMode === "tabler" ? "file" : "text-x-generic";
      else if (item.contentType === "code")
        defaultIcon = iconMode === "tabler" ? "code" : "text-x-script";
      else if (item.contentType === "color") {
        defaultIcon = iconMode === "tabler" ? "palette" : "color-picker";
        colorHex = preview;
      }
    }

    return {
      "name": title,
      "description": description,
      "icon": defaultIcon,
      "isTablerIcon": true,
      "isImage": false,
      "clipboardId": item.id,
      "preview": preview,
      "contentType": item.contentType,
      "colorHex": colorHex,
      "provider": root
    };
  }

  function getImageForItem(clipboardId) {
    return ClipboardService.getImageData ? ClipboardService.getImageData(clipboardId) : null;
  }

  // -------------------------
  // Item actions for launcher delegate
  function getItemActions(item) {
    if (!item || !item.clipboardId)
      return [];

    var actions = [];

    // Annotation tool for images
    if (item.isImage && Settings.data.appLauncher.screenshotAnnotationTool !== "") {
      actions.push({
                     "icon": "pencil",
                     "tooltip": I18n.tr("tooltips.open-annotation-tool"),
                     "action": function () {
                       var tool = Settings.data.appLauncher.screenshotAnnotationTool;
                       Quickshell.execDetached(["sh", "-c", "cliphist decode " + item.clipboardId + " | " + tool]);
                       if (launcher)
                         launcher.close();
                     }
                   });
    }

    // Delete action
    actions.push({
                   "icon": "trash",
                   "tooltip": I18n.tr("launcher.providers.clipboard-delete"),
                   "action": function () {
                     deleteItem(item);
                   }
                 });

    return actions;
  }

  function canDeleteItem(item) {
    return item && !!item.clipboardId;
  }

  function deleteItem(item) {
    if (!item || !item.clipboardId)
      return;

    // Set provider state before deletion so refresh works
    gotResults = false;
    isWaitingForData = true;
    lastSearchText = launcher ? launcher.searchText : "";

    // Delete the item
    ClipboardService.deleteById(String(item.clipboardId));
  }

  // Prepare item for display (handles image decoding)
  function prepareItem(item) {
    if (item && item.isImage && item.clipboardId) {
      if (!ClipboardService.getImageData(item.clipboardId)) {
        ClipboardService.decodeToDataUrl(item.clipboardId, item.mime, null);
      }
    }
  }

  // Get image URL for item (used by delegates)
  function getImageUrl(item) {
    if (!item || !item.clipboardId)
      return "";
    return ClipboardService.getImageData(item.clipboardId) || "";
  }

  // Get preview data for the preview panel
  function getPreviewData(item) {
    if (!item)
      return null;
    return {
      "clipboardId": item.clipboardId,
      "isImage": item.isImage,
      "mime": item.mime,
      "preview": item.preview
    };
  }
}
