"use client";

import type { FileTreeRow } from "./types";
import { parseFileTreeRowId } from "./types";

export type FileTreeClipboardAction = "copy";

export type FileTreeClipboardPayloadV1 = {
  type: "mnote-file-tree";
  version: 1;
  action: FileTreeClipboardAction;
  rowIds: string[];
};

const PREFIX = "mnote-file-tree-clipboard:v1:";

let memoryClipboardText: string | null = null;

function encodeBase64(text: string): string {
  const bytes = new TextEncoder().encode(text);
  let binary = "";
  bytes.forEach((b) => {
    binary += String.fromCharCode(b);
  });
  return btoa(binary);
}

function decodeBase64(base64: string): string {
  const binary = atob(base64);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i += 1) {
    bytes[i] = binary.charCodeAt(i);
  }
  return new TextDecoder().decode(bytes);
}

export function encodeFileTreeClipboardPayload(payload: FileTreeClipboardPayloadV1): string {
  return `${PREFIX}${encodeBase64(JSON.stringify(payload))}`;
}

export function decodeFileTreeClipboardPayload(text: string): FileTreeClipboardPayloadV1 | null {
  if (!text || !text.startsWith(PREFIX)) return null;
  const base64 = text.slice(PREFIX.length);
  try {
    const raw = decodeBase64(base64);
    const parsed = JSON.parse(raw) as Partial<FileTreeClipboardPayloadV1>;
    if (parsed?.type !== "mnote-file-tree" || parsed.version !== 1) return null;
    if (parsed.action !== "copy") return null;
    if (!Array.isArray(parsed.rowIds) || parsed.rowIds.some((id) => typeof id !== "string")) return null;
    return parsed as FileTreeClipboardPayloadV1;
  } catch {
    return null;
  }
}

export async function writeFileTreeClipboardPayload(payload: FileTreeClipboardPayloadV1): Promise<void> {
  const text = encodeFileTreeClipboardPayload(payload);
  memoryClipboardText = text;
  if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
    try {
      await navigator.clipboard.writeText(text);
    } catch {
      // ignore, fallback to memory
    }
  }
}

export async function readFileTreeClipboardPayload(): Promise<FileTreeClipboardPayloadV1 | null> {
  let text: string | null = memoryClipboardText;
  if (typeof navigator !== "undefined" && navigator.clipboard?.readText) {
    try {
      text = await navigator.clipboard.readText();
    } catch {
      // ignore, fallback to memory
    }
  }
  if (!text) return null;
  return decodeFileTreeClipboardPayload(text);
}

export function isTextInputTarget(target: EventTarget | null): boolean {
  const el = target as HTMLElement | null;
  if (!el) return false;
  if (el.isContentEditable) return true;
  const contentEditable = el.getAttribute?.("contenteditable");
  if (contentEditable && contentEditable.toLowerCase() !== "false") {
    return true;
  }
  const tag = el.tagName?.toLowerCase();
  return tag === "input" || tag === "textarea" || el.getAttribute?.("role") === "textbox";
}

export function inferPasteTargetDocId({
  focusedRowId,
  rowById,
  activeDocId,
}: {
  focusedRowId: string | null;
  rowById: Map<string, FileTreeRow>;
  activeDocId: string | null;
}): string | null {
  if (focusedRowId) {
    const parsed = parseFileTreeRowId(focusedRowId);
    if (parsed?.kind === "doc") return parsed.docId;
    if (parsed?.kind === "index") return parsed.docId;
    if (parsed?.kind === "asset-folder") {
      const row = rowById.get(focusedRowId);
      return row?.kind === "asset-folder" ? row.docId : null;
    }
    if (parsed?.kind === "asset") {
      const row = rowById.get(focusedRowId);
      return row?.kind === "asset" ? row.docId : null;
    }
  }
  return activeDocId || null;
}
