import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

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

export async function copyTextToClipboard(text: string): Promise<boolean> {
  if (typeof window === 'undefined' || typeof document === 'undefined') return false;

  const value = text.trim();
  if (!value) return false;

  if (navigator.clipboard?.writeText && window.isSecureContext) {
    try {
      await navigator.clipboard.writeText(value);
      return true;
    } catch {
      // Fall back below. Some browsers expose the API but still reject it.
    }
  }

  const textarea = document.createElement('textarea');
  textarea.value = value;
  textarea.setAttribute('readonly', '');
  textarea.style.position = 'fixed';
  textarea.style.left = '0';
  textarea.style.top = '0';
  textarea.style.width = '1px';
  textarea.style.height = '1px';
  textarea.style.padding = '0';
  textarea.style.border = '0';
  textarea.style.outline = '0';
  textarea.style.boxShadow = 'none';
  textarea.style.opacity = '0';
  document.body.appendChild(textarea);

  const selection = document.getSelection();
  const previousRange = selection && selection.rangeCount > 0 ? selection.getRangeAt(0).cloneRange() : null;
  const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;

  try {
    textarea.focus();
    textarea.select();
    textarea.setSelectionRange(0, value.length);
    return document.execCommand('copy') || document.execCommand('copy', false, value);
  } catch {
    return false;
  } finally {
    document.body.removeChild(textarea);
    previousFocus?.focus({ preventScroll: true });
    if (selection && previousRange) {
      selection.removeAllRanges();
      selection.addRange(previousRange);
    }
  }
}

/**
 * Download a file from a URL using the server-side proxy to bypass CORS.
 *
 * Why not fetch() directly? S3 presigned URLs and other remote URLs
 * often don't have CORS headers for the browser origin, causing
 * client-side fetch() to fail. The /api/download proxy fetches
 * server-side (no CORS restriction) and returns the file with
 * Content-Disposition header.
 */
export async function downloadFile(
  url: string,
  filename: string,
): Promise<{ ok: true } | { ok: false; error: string }> {
  try {
    const proxyUrl = `/api/download?url=${encodeURIComponent(url)}&filename=${encodeURIComponent(filename)}`;
    const response = await fetch(proxyUrl);

    if (!response.ok) {
      const data = await response.json().catch(() => ({ error: '下载失败' }));
      return { ok: false, error: data.error || '下载失败' };
    }

    const blob = await response.blob();
    const blobUrl = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = blobUrl;
    link.download = filename;
    link.click();
    URL.revokeObjectURL(blobUrl);
    return { ok: true };
  } catch (err) {
    const msg = err instanceof Error ? err.message : '下载失败';
    return { ok: false, error: msg };
  }
}

/**
 * Safely parse a fetch Response as JSON.
 * Handles empty bodies, HTML error pages, and non-JSON responses gracefully.
 * Returns { ok, data, error } instead of throwing.
 */
export async function safeParseJson<T = Record<string, unknown>>(res: Response): Promise<{
  ok: boolean;
  data: T | null;
  error: string | null;
}> {
  // Check Content-Type to detect HTML responses early
  const contentType = res.headers.get('content-type') || '';
  const isJson = contentType.includes('application/json');

  if (!res.ok) {
    // Error response - try to extract meaningful message
    try {
      const text = await res.text();

      // HTML error page (Cloudflare, nginx, etc.)
      if (text.trim().startsWith('<!') || text.trim().startsWith('<html') || text.trim().startsWith('<HTML')) {
        return {
          ok: false,
          data: null,
          error: `服务器返回错误页面 (HTTP ${res.status})，可能原因：API 服务异常或代理防火墙拦截了请求`,
        };
      }

      // Try parsing as JSON error
      try {
        const json = JSON.parse(text);
        const errorMsg = json.error || json.message || json.msg || `请求失败 (HTTP ${res.status})`;
        return { ok: false, data: null, error: typeof errorMsg === 'string' ? errorMsg : String(errorMsg) };
      } catch {
        // Plain text error
        return {
          ok: false,
          data: null,
          error: text.slice(0, 200) || `请求失败 (HTTP ${res.status})`,
        };
      }
    } catch {
      return { ok: false, data: null, error: `请求失败 (HTTP ${res.status})` };
    }
  }

  // Success response - parse JSON
  try {
    const text = await res.text();

    if (!text.trim()) {
      return { ok: false, data: null, error: '服务器返回了空响应' };
    }

    try {
      const data = JSON.parse(text) as T;
      return { ok: true, data, error: null };
    } catch {
      // Response is not JSON
      if (!isJson && (text.trim().startsWith('<!') || text.trim().startsWith('<html'))) {
        return { ok: false, data: null, error: '服务器返回了错误页面而非 JSON 数据，可能是代理防火墙拦截' };
      }
      return { ok: false, data: null, error: '服务器返回了无法解析的响应' };
    }
  } catch {
    return { ok: false, data: null, error: '读取响应失败' };
  }
}
