'use client';

import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
  Trash2,
  Download,
  Loader2,
  FolderOpen,
  Folder,
  FileText,
  Upload,
  FolderPlus,
  ChevronRight,
  Home,
  RefreshCw,
  FileImage,
  FileCode,
  FileArchive,
  FileSpreadsheet,
} from 'lucide-react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import {
  browseUserFiles,
  getUserFile,
  getUserFileDownloadUrl,
  uploadUserFile,
  deleteUserFile,
  createUserFileDir,
  getAccessToken,
  isApiError,
} from '@/lib/api';
import type { UserFileContent, UserFileItem } from '@/lib/api';
import { canMutateUserFilesPath } from '@/lib/user-file-paths';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { type AppLocale, pickAppText } from '@/lib/i18n/core';
import { useAppI18n } from '@/lib/i18n/provider';
import { containedLongTextClass, containedPreservedLongTextClass } from '@/lib/text-wrapping';

const LOAD_RETRY_DELAYS_MS = [0, 600, 1200];

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => {
    window.setTimeout(resolve, ms);
  });
}

function isAuthError(error: unknown): boolean {
  return isApiError(error, 401);
}

export default function FilesPage() {
  const { locale } = useAppI18n();
  const [items, setItems] = useState<UserFileItem[]>([]);
  const [currentPath, setCurrentPath] = useState('');
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [uploading, setUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState(0);
  const [showMkdir, setShowMkdir] = useState(false);
  const [newDirName, setNewDirName] = useState('');
  const [selectedFile, setSelectedFile] = useState<UserFileContent | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [previewError, setPreviewError] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const mkdirInputRef = useRef<HTMLInputElement>(null);

  const load = useCallback(async (path: string = currentPath) => {
    let lastError: unknown = null;
    try {
      setLoading(true);
      setLoadError(null);
      for (const delay of LOAD_RETRY_DELAYS_MS) {
        if (delay > 0) {
          await sleep(delay);
        }
        try {
          const data = await browseUserFiles(path);
          setItems(data.items);
          setCurrentPath(data.path);
          setSelectedFile(null);
          setPreviewError(null);
          return;
        } catch (err) {
          lastError = err;
          if (isAuthError(err)) {
            break;
          }
        }
      }
      const message = lastError instanceof Error ? lastError.message : pickAppText(locale, '加载文件失败', 'Failed to load files');
      setLoadError(message);
      setItems([]);
    } finally {
      setLoading(false);
    }
  }, [currentPath, locale]);

  useEffect(() => {
    load('');
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  const navigateTo = (path: string) => {
    load(path);
  };

  const openFile = async (item: UserFileItem) => {
    if (item.type !== 'file') return;
    setPreviewLoading(true);
    setPreviewError(null);
    try {
      setSelectedFile(await getUserFile(item.path));
    } catch (err: any) {
      setPreviewError(err.message || pickAppText(locale, '加载文件失败', 'Failed to load file'));
      setSelectedFile(null);
    } finally {
      setPreviewLoading(false);
    }
  };

  const handleDelete = async (item: UserFileItem) => {
    const label = item.type === 'directory'
      ? pickAppText(locale, '文件夹', 'folder')
      : pickAppText(locale, '文件', 'file');
    if (!confirm(pickAppText(
      locale,
      `确定删除${label} "${item.name}"？${item.type === 'directory' ? '（包含所有子文件）' : ''}`,
      `Delete ${label} "${item.name}"?${item.type === 'directory' ? ' (including all nested files)' : ''}`
    ))) {
      return;
    }
    try {
      await deleteUserFile(item.path);
      setItems((prev) => prev.filter((i) => i.path !== item.path));
      if (selectedFile?.path === item.path) {
        setSelectedFile(null);
      }
    } catch (err: any) {
      setLoadError(err.message || pickAppText(locale, '删除失败', 'Delete failed'));
    }
  };

  const handleDownload = async (item: UserFileItem) => {
    const url = getUserFileDownloadUrl(item.path);
    const token = getAccessToken();
    const headers: Record<string, string> = {};
    if (token) headers['Authorization'] = `Bearer ${token}`;

    try {
      const res = await fetch(url, { headers });
      const blob = await res.blob();
      const a = document.createElement('a');
      a.href = URL.createObjectURL(blob);
      a.download = item.name;
      document.body.appendChild(a);
      a.click();
      a.remove();
      URL.revokeObjectURL(a.href);
    } catch (err: any) {
      setPreviewError(err.message || pickAppText(locale, '下载失败', 'Download failed'));
    }
  };

  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files || files.length === 0) return;
    if (!canMutateUserFilesPath(currentPath)) {
      setLoadError(pickAppText(
        locale,
        '请先进入 uploads、outputs、shared 或 tasks 目录后再上传。',
        'Open uploads, outputs, shared, or tasks before uploading.'
      ));
      if (fileInputRef.current) fileInputRef.current.value = '';
      return;
    }

    setUploading(true);
    setUploadProgress(0);
    try {
      for (let i = 0; i < files.length; i++) {
        await uploadUserFile(files[i], currentPath, (pct) => {
          setUploadProgress(Math.round((i / files.length) * 100 + pct / files.length));
        });
      }
      await load();
    } catch (err: any) {
      setLoadError(err.message || pickAppText(locale, '上传失败', 'Upload failed'));
    } finally {
      setUploading(false);
      setUploadProgress(0);
      if (fileInputRef.current) fileInputRef.current.value = '';
    }
  };

  const handleCreateDir = async () => {
    const name = newDirName.trim();
    if (!name) return;
    if (!canMutateUserFilesPath(currentPath)) {
      setLoadError(pickAppText(
        locale,
        '请先进入 uploads、outputs、shared 或 tasks 目录后再新建文件夹。',
        'Open uploads, outputs, shared, or tasks before creating a folder.'
      ));
      return;
    }
    try {
      const dirPath = currentPath ? `${currentPath}/${name}` : name;
      await createUserFileDir(dirPath);
      setShowMkdir(false);
      setNewDirName('');
      await load();
    } catch (err: any) {
      setLoadError(err.message || pickAppText(locale, '创建文件夹失败', 'Failed to create folder'));
    }
  };

  // Build breadcrumbs
  const breadcrumbs = currentPath ? currentPath.split('/') : [];
  const canMutateCurrentPath = canMutateUserFilesPath(currentPath);

  const formatSize = (bytes: number | null) => {
    if (bytes === null || bytes === undefined) return '';
    if (bytes > 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
    if (bytes > 1024) return `${(bytes / 1024).toFixed(0)} KB`;
    return `${bytes} B`;
  };

  const formatDate = (iso: string | null | undefined) => {
    if (!iso) return '';
    try {
      return new Date(iso).toLocaleString(locale, {
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
      });
    } catch {
      return '';
    }
  };

  return (
    <div className="mx-auto w-full max-w-7xl overflow-x-hidden px-4 py-6 sm:px-6">
      {/* Header */}
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
        <h1 className="text-2xl font-bold">{pickAppText(locale, '文件管理', 'Files')}</h1>
        <div className="flex flex-wrap items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            className="h-11"
            onClick={() => setShowMkdir(true)}
            disabled={loading || !canMutateCurrentPath}
            title={
              canMutateCurrentPath
                ? undefined
                : pickAppText(locale, '先进入 uploads、outputs、shared 或 tasks', 'Open uploads, outputs, shared, or tasks first')
            }
          >
            <FolderPlus className="w-4 h-4 mr-1" />
            {pickAppText(locale, '新建文件夹', 'New folder')}
          </Button>
          <Button
            variant="outline"
            size="sm"
            className="h-11"
            onClick={() => fileInputRef.current?.click()}
            disabled={uploading || !canMutateCurrentPath}
            title={
              canMutateCurrentPath
                ? undefined
                : pickAppText(locale, '先进入 uploads、outputs、shared 或 tasks', 'Open uploads, outputs, shared, or tasks first')
            }
          >
            {uploading ? (
              <>
                <Loader2 className="w-4 h-4 mr-1 animate-spin" />
                {uploadProgress}%
              </>
            ) : (
              <>
                <Upload className="w-4 h-4 mr-1" />
                {pickAppText(locale, '上传', 'Upload')}
              </>
            )}
          </Button>
          <input
            ref={fileInputRef}
            type="file"
            multiple
            className="hidden"
            onChange={handleUpload}
          />
          <Button
            variant="outline"
            size="icon"
            className="h-11 w-11"
            onClick={() => load()}
            disabled={loading}
            aria-label={pickAppText(locale, '刷新', 'Refresh')}
            title={pickAppText(locale, '刷新', 'Refresh')}
          >
            {loading ? (
              <Loader2 className="w-4 h-4 animate-spin" />
            ) : (
              <RefreshCw className="w-4 h-4" />
            )}
          </Button>
        </div>
      </div>
      {!canMutateCurrentPath && !loading && (
        <p className="mb-4 rounded-md border border-[#E6E1DE] bg-muted/40 px-3 py-2 text-sm text-muted-foreground">
          {pickAppText(
            locale,
            '请选择 uploads、outputs、shared 或 tasks 后再上传或新建文件夹。',
            'Select uploads, outputs, shared, or tasks before uploading or creating folders.'
          )}
        </p>
      )}

      {/* Breadcrumbs */}
      <div className="flex items-center gap-1 mb-4 text-sm text-muted-foreground flex-wrap">
        <button
          onClick={() => navigateTo('')}
          className="inline-flex h-11 items-center gap-1 rounded px-2 transition-colors hover:bg-accent hover:text-foreground"
        >
          <Home className="w-3.5 h-3.5" />
          {pickAppText(locale, '文件', 'Files')}
        </button>
        {breadcrumbs.map((segment, idx) => {
          const path = breadcrumbs.slice(0, idx + 1).join('/');
          const isLast = idx === breadcrumbs.length - 1;
          return (
            <React.Fragment key={path}>
              <ChevronRight className="w-3 h-3 flex-shrink-0" />
              <button
                onClick={() => navigateTo(path)}
                className={`inline-flex h-11 items-center rounded px-2 text-left transition-colors ${containedLongTextClass} ${
                  isLast
                    ? 'text-foreground font-medium'
                    : 'hover:text-foreground hover:bg-accent'
                }`}
              >
                {segment}
              </button>
            </React.Fragment>
          );
        })}
      </div>

      {/* New directory input */}
      {showMkdir && (
        <div className="mb-4 flex flex-wrap items-center gap-2">
          <Folder className="w-4 h-4 text-muted-foreground" />
          <label htmlFor="new-folder-name" className="sr-only">
            {pickAppText(locale, '文件夹名称', 'Folder name')}
          </label>
          <input
            id="new-folder-name"
            ref={mkdirInputRef}
            type="text"
            value={newDirName}
            onChange={(e) => setNewDirName(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === 'Enter') handleCreateDir();
              if (e.key === 'Escape') {
                setShowMkdir(false);
                setNewDirName('');
              }
            }}
            placeholder={pickAppText(locale, '文件夹名称', 'Folder name')}
            className="h-11 min-w-0 flex-1 rounded-md border border-border bg-background px-3 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
            autoFocus
          />
          <Button size="sm" className="h-11" onClick={handleCreateDir}>
            {pickAppText(locale, '创建', 'Create')}
          </Button>
          <Button
            size="sm"
            variant="ghost"
            className="h-11"
            onClick={() => {
              setShowMkdir(false);
              setNewDirName('');
            }}
          >
            {pickAppText(locale, '取消', 'Cancel')}
          </Button>
        </div>
      )}

      <div className="grid min-w-0 grid-cols-[minmax(0,1fr)] gap-4 lg:grid-cols-[minmax(360px,440px)_minmax(0,1fr)]">
        {/* File list */}
        <div className="min-w-0 rounded-lg border border-border bg-card lg:min-h-[520px]">
          {loading && items.length === 0 ? (
            <div className="flex items-center justify-center py-20 text-muted-foreground">
              <Loader2 className="w-6 h-6 animate-spin" />
            </div>
          ) : loadError ? (
            <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
              <FolderOpen className="w-12 h-12 mb-4 opacity-50" />
              <p className="text-lg font-medium">{pickAppText(locale, '加载失败', 'Failed to load')}</p>
              <p className="max-w-sm text-center text-sm">{loadError}</p>
              <Button className="mt-4 h-11" variant="outline" size="sm" onClick={() => load()}>
                <RefreshCw className="mr-1 h-4 w-4" />
                {pickAppText(locale, '重试', 'Retry')}
              </Button>
            </div>
          ) : items.length === 0 ? (
            <div className="flex flex-col items-center justify-center py-20 text-muted-foreground">
              <FolderOpen className="w-12 h-12 mb-4 opacity-50" />
              <p className="text-lg font-medium">{pickAppText(locale, '空文件夹', 'Empty folder')}</p>
              <p className="px-4 text-center text-sm">{pickAppText(locale, '点击上方"上传"或"新建文件夹"按钮开始使用', 'Use "Upload" or "New folder" above to get started')}</p>
            </div>
          ) : (
            <ScrollArea className="max-h-[calc(100vh-15rem)] min-h-[360px] lg:min-h-[520px]">
              <div className="space-y-1 p-2">
                {items.map((item) => (
                  <div
                    key={item.path}
                    className={`group flex min-w-0 flex-col gap-2 rounded-lg border p-2 text-left transition-colors hover:bg-accent/30 sm:flex-row sm:items-center ${
                      selectedFile?.path === item.path ? 'border-primary bg-accent/40' : 'border-border bg-card'
                    }`}
                  >
                    <button
                      type="button"
                      className="flex min-h-[3.5rem] min-w-0 flex-1 items-center gap-3 rounded-md px-1 py-2 text-left"
                      onClick={() => {
                        if (item.type === 'directory') {
                          navigateTo(item.path);
                        } else {
                          void openFile(item);
                        }
                      }}
                    >
                      <div className="flex-shrink-0">
                        {item.type === 'directory' ? (
                          <Folder className="w-5 h-5 text-blue-500" />
                        ) : (
                          <FileIcon name={item.name} contentType={item.content_type || undefined} />
                        )}
                      </div>

                      <div className="min-w-0 flex-1">
                        <div className={`text-sm font-medium ${containedLongTextClass}`}>{item.name}</div>
                        <p className={`text-xs text-muted-foreground ${containedLongTextClass}`}>
                          {item.type === 'file' && formatSize(item.size)}
                          {item.modified && (
                            <>
                              {item.type === 'file' && ' · '}
                              {formatDate(item.modified)}
                            </>
                          )}
                        </p>
                      </div>
                    </button>

                    <div className="flex shrink-0 items-center justify-end gap-1 opacity-100 md:opacity-0 md:transition-opacity md:group-hover:opacity-100">
                      {item.type === 'file' && (
                        <button
                          type="button"
                          className="inline-flex h-11 w-11 items-center justify-center rounded-md hover:bg-accent"
                          onClick={(event) => {
                            event.stopPropagation();
                            void handleDownload(item);
                          }}
                          aria-label={`${pickAppText(locale, '下载', 'Download')} ${item.name}`}
                          title={pickAppText(locale, '下载', 'Download')}
                        >
                          <Download className="w-4 h-4" />
                        </button>
                      )}
                      <button
                        type="button"
                        className="inline-flex h-11 w-11 items-center justify-center rounded-md text-destructive hover:bg-accent hover:text-destructive"
                        onClick={(event) => {
                          event.stopPropagation();
                          void handleDelete(item);
                        }}
                        aria-label={`${pickAppText(locale, '删除', 'Delete')} ${item.name}`}
                        title={pickAppText(locale, '删除', 'Delete')}
                      >
                        <Trash2 className="w-4 h-4" />
                      </button>
                    </div>
                  </div>
                ))}
              </div>
            </ScrollArea>
          )}
        </div>

        <FilePreviewPanel
          file={selectedFile}
          loading={previewLoading}
          error={previewError}
          formatSize={formatSize}
          formatDate={formatDate}
          downloadUrl={selectedFile ? getUserFileDownloadUrl(selectedFile.path) : null}
          locale={locale}
        />
      </div>
    </div>
  );
}

function FilePreviewPanel({
  file,
  loading,
  error,
  formatSize,
  formatDate,
  downloadUrl,
  locale,
}: {
  file: UserFileContent | null;
  loading: boolean;
  error: string | null;
  formatSize: (bytes: number | null) => string;
  formatDate: (iso: string | null | undefined) => string;
  downloadUrl: string | null;
  locale: AppLocale;
}) {
  return (
    <div className="min-w-0 rounded-lg border border-border bg-card p-4 lg:min-h-[520px]">
      {loading ? (
        <div className="flex h-[420px] items-center justify-center text-muted-foreground">
          <Loader2 className="h-6 w-6 animate-spin" />
        </div>
      ) : error ? (
        <div className="flex h-[420px] items-center justify-center text-center text-sm text-destructive">{error}</div>
      ) : !file ? (
        <div className="flex h-[420px] flex-col items-center justify-center text-center text-muted-foreground">
          <FileText className="mb-3 h-10 w-10 opacity-50" />
          <p className="text-sm font-medium">{pickAppText(locale, '点击左侧文件查看内容', 'Click a file to preview its contents')}</p>
        </div>
      ) : (
        <div className="space-y-3">
          <div className="flex min-w-0 flex-wrap items-start justify-between gap-3 border-b border-border pb-3">
            <div className="min-w-0">
              <h2 className={`text-base font-semibold ${containedLongTextClass}`}>{file.name}</h2>
              <p className={`mt-1 text-xs text-muted-foreground ${containedLongTextClass}`}>
                {formatSize(file.size)} · {formatDate(file.modified)} · {file.content_type}
                {file.is_truncated ? ` · ${pickAppText(locale, '仅预览前 1MB', 'Showing first 1MB')}` : ''}
              </p>
            </div>
            {downloadUrl && (
              <Button variant="outline" size="sm" className="h-11" asChild>
                <a href={downloadUrl}>
                  <Download className="mr-2 h-4 w-4" />
                  {pickAppText(locale, '下载', 'Download')}
                </a>
              </Button>
            )}
          </div>

          {isImage(file) && downloadUrl ? (
            <div className="flex max-h-[620px] items-start justify-center overflow-auto rounded-md border border-border bg-muted/20 p-3">
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={downloadUrl} alt={file.name} className="max-h-[580px] max-w-full object-contain" />
            </div>
          ) : file.is_binary ? (
            <div className="flex h-[360px] flex-col items-center justify-center text-center text-muted-foreground">
              <FileArchive className="mb-3 h-10 w-10 opacity-50" />
              <p className="text-sm font-medium">{pickAppText(locale, '该文件不能直接预览', 'This file cannot be previewed')}</p>
            </div>
          ) : isMarkdown(file) ? (
            <div className={`prose prose-sm max-h-[620px] max-w-none overflow-auto text-black prose-a:text-black prose-code:text-black prose-headings:text-black prose-li:text-black prose-p:text-black prose-pre:bg-muted prose-pre:text-black prose-strong:text-black [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_*]:min-w-0 ${containedLongTextClass}`}>
              <ReactMarkdown remarkPlugins={[remarkGfm]}>{file.content || ''}</ReactMarkdown>
            </div>
          ) : (
            <pre className={`max-h-[620px] overflow-auto rounded-md border border-border bg-background p-4 text-xs leading-5 text-black ${containedPreservedLongTextClass}`}>
              {file.content || ''}
            </pre>
          )}
        </div>
      )}
    </div>
  );
}

function FileIcon({ name, contentType }: { name: string; contentType?: string }) {
  const ext = name.split('.').pop()?.toLowerCase() || '';
  const ct = contentType || '';

  if (ct.startsWith('image/') || ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext)) {
    return <FileImage className="w-5 h-5 text-green-500" />;
  }
  if (
    ['js', 'ts', 'tsx', 'jsx', 'py', 'rb', 'go', 'rs', 'java', 'c', 'cpp', 'h', 'css', 'html', 'json', 'yaml', 'yml', 'toml', 'md', 'sh'].includes(ext)
  ) {
    return <FileCode className="w-5 h-5 text-orange-500" />;
  }
  if (['zip', 'tar', 'gz', 'bz2', 'rar', '7z', 'xz'].includes(ext)) {
    return <FileArchive className="w-5 h-5 text-yellow-500" />;
  }
  if (['csv', 'xls', 'xlsx', 'tsv'].includes(ext)) {
    return <FileSpreadsheet className="w-5 h-5 text-emerald-500" />;
  }
  return <FileText className="w-5 h-5 text-muted-foreground" />;
}

function isImage(file: UserFileContent): boolean {
  return file.content_type.startsWith('image/');
}

function isMarkdown(file: UserFileContent): boolean {
  return file.path.toLowerCase().endsWith('.md') || file.content_type.includes('markdown');
}
