import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
import { isDesktopShell } from "@/lib/desktop";
import { matchesFuzzyQuery } from "@/lib/search/fuzzySearch";
import type { I18nKey } from "@/lib/i18n";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

/**
 * Detects if the current platform is macOS.
 * Uses navigator.userAgent in browser environments.
 */
export const isMacOS = (): boolean => {
  if (typeof navigator === 'undefined') return false;
  return /Macintosh|Mac OS X/.test(navigator.userAgent || '');
};

const isWindows = (): boolean => {
  if (typeof navigator === 'undefined') return false;
  return /Windows/.test(navigator.userAgent || '');
};

export const getRevealLabelKey = (): I18nKey => {
  if (isMacOS()) return 'common.revealPath.finder';
  if (isWindows()) return 'common.revealPath.fileExplorer';
  return 'common.revealPath.fileManager';
};

/**
 * Checks if the platform-appropriate modifier key is pressed.
 * On macOS desktop app: Cmd (metaKey), on other platforms or web: Ctrl (ctrlKey).
 * Browser intercepts Cmd shortcuts, so we only use Cmd in the desktop app.
 */
export const hasModifier = (e: KeyboardEvent | React.KeyboardEvent): boolean => {
  return isMacOS() && isDesktopShell() ? e.metaKey : e.ctrlKey;
};

/**
 * Returns the platform-appropriate modifier key label.
 * On macOS desktop app: "⌘", on other platforms or web: "Ctrl"
 * Browser intercepts Cmd shortcuts, so we only show Cmd in the desktop app.
 */
export const getModifierLabel = (): string => {
  return isMacOS() && isDesktopShell() ? '⌘' : 'Ctrl';
};

export const truncatePathMiddle = (
  value: string,
  options?: { maxLength?: number }
): string => {
  const source = value ?? "";
  const maxLength = Math.max(16, options?.maxLength ?? 45);
  if (source.length <= maxLength) {
    return source;
  }

  const segments = source.split('/');
  if (segments.length <= 1) {
    return source;
  }

  const fileName = segments.pop() ?? '';
  if (!fileName) {
    return source;
  }

  const prefixBudget = Math.max(0, maxLength - (fileName.length + 2));
  if (prefixBudget <= 0) {
    return `…/${fileName}`;
  }

  let prefix = '';
  for (const segment of segments) {
    if (!segment) {
      continue;
    }
    const candidate = prefix ? `${prefix}/${segment}` : segment;
    if (candidate.length > prefixBudget) {
      break;
    }
    prefix = candidate;
  }

  if (!prefix) {
    const first = segments[0] ?? '';
    prefix = first ? first.slice(0, prefixBudget) : '';
  }

  return prefix ? `${prefix}…/${fileName}` : `…/${fileName}`;
};

const normalizePath = (value: string) => {
  if (!value) return "";
  if (value === "/") return "/";
  return value.replace(/\/+$/, "");
};

export function formatPathForDisplay(path: string | null | undefined, homeDirectory?: string | null): string {
  if (!path) {
    return "";
  }

  const normalizedPath = normalizePath(path);
  if (normalizedPath === "/") {
    return "/";
  }

  const normalizedHome = homeDirectory ? normalizePath(homeDirectory) : undefined;

  if (normalizedHome && normalizedHome !== "/") {
    if (normalizedPath === normalizedHome) {
      return "~";
    }
    if (normalizedPath.startsWith(`${normalizedHome}/`)) {
      const relative = normalizedPath.slice(normalizedHome.length + 1);
      return relative ? `~/${relative}` : "~";
    }
  }

  return normalizedPath;
}

export function formatDirectoryName(path: string | null | undefined, homeDirectory?: string | null): string {
  if (!path) {
    return "/";
  }

  const normalizedPath = normalizePath(path);
  if (!normalizedPath || normalizedPath === "/") {
    return "/";
  }

  const normalizedHome = homeDirectory ? normalizePath(homeDirectory) : undefined;
  if (normalizedHome && normalizedHome !== "/" && normalizedPath === normalizedHome) {
    return "~";
  }

  const segments = normalizedPath.split("/");
  const name = segments.pop() || normalizedPath;
  return name || "/";
}

/**
 * Fuzzy search using Fuse.js with typo tolerance.
 * Returns true if query fuzzy-matches target (e.g. "coude" matches "claude")
 */
export function fuzzyMatch(target: string, query: string): boolean {
  return matchesFuzzyQuery(target, query);
}
