import { i18n } from '../locales';

export interface FileEntry {
  name: string;
  path: string;
  isDirectory: boolean;
  size?: number;
  modifiedAt?: number;
  children?: FileEntry[];
}

/**
 * 文件服务客户端接口
 *
 * 增加了 openFolder / openFile / saveFileAs 等 UI 交互方法。
 * 三种实现分别对应 Electron IPC、Server REST API、Browser File System Access API。
 */
export interface FileServiceClient {
  rootName?: string;
  readFile(path: string): Promise<string>;
  readFileBuffer(path: string): Promise<ArrayBuffer>;
  writeFile(path: string, content: string): Promise<void>;
  deleteFile(path: string): Promise<void>;
  readDir(path: string): Promise<FileEntry[]>;
  createDir(path: string): Promise<void>;
  deleteDir(path: string, recursive?: boolean): Promise<void>;
  exists(path: string): Promise<boolean>;
  stat(path: string): Promise<FileEntry>;
  rename(oldPath: string, newPath: string): Promise<void>;
  openFolderPath?(path: string): Promise<string | null>;
  openFolder(): Promise<string | null>;
  openFile(): Promise<{ path: string } | null>;
  saveFileAs?(path: string, content: string): Promise<string | null>;
  browseFilesystem(path: string): Promise<{ path: string; parent: string; entries: FileEntry[] }>;
  getWorkspaceRoots(): Promise<FileEntry[]>;
  openWorkspace(rootPath: string, providerConfig?: Record<string, unknown>, lightweight?: boolean): Promise<WorkspaceInfo>;
  closeWorkspace(workspaceId: string): Promise<void>;
  updateWorkspace(workspaceId: string, data: { openTabs?: StoredTabInfo[]; activeTabPath?: string }): Promise<void>;
  getWorkspaceSessions(workspaceId: string): Promise<WorkspaceAgentSession[]>;
  saveWorkspaceSession(workspaceId: string, session: WorkspaceAgentSession): Promise<void>;
  deleteWorkspaceSession(workspaceId: string, sessionId: string): Promise<void>;
  setWorkspaceRoot?(root: string): void;
}

export interface StoredTabInfo {
  path: string;
  cursorLine?: number;
  cursorColumn?: number;
}

export interface WorkspaceAgentSession {
  id: string;
  name: string;
  nameAutoGenerated: boolean;
  createdAt: number;
  lastMessageAt?: number;
  messages: { id: string; role: string; content: string; timestamp: number; agentId?: string }[];
}

export interface WorkspaceInfo {
  workspaceId: string;
  rootPath: string;
  rootName: string;
  openTabs: StoredTabInfo[];
  activeTabPath?: string;
  createdAt: number;
  lastOpenedAt: number;
  agentSessions?: WorkspaceAgentSession[];
}

/** 运行时环境类型 */
export type RuntimeEnv = 'electron' | 'server' | 'browser';

let cachedEnv: RuntimeEnv | null = null;

/**
 * 检测运行时环境（结果缓存）
 *
 * 检测顺序：electron → browser → server
 * - electron: window.electronAPI 存在
 * - browser:  showDirectoryPicker 存在（File System Access API）
 * - server:   以上均无（回退到 HTTP REST）
 */
export function detectEnvironment(): RuntimeEnv {
  if (cachedEnv) return cachedEnv;
  if (typeof window !== 'undefined' && window.electronAPI) {
    cachedEnv = 'electron';
  } else if (typeof window !== 'undefined' && 'showDirectoryPicker' in window) {
    cachedEnv = 'browser';
  } else {
    cachedEnv = 'server';
  }
  return cachedEnv;
}

/** 创建 Electron IPC 客户端 —— 通过 window.electronAPI 桥接主进程文件操作 */
export function createElectronClient(): FileServiceClient {
  const api = window.electronAPI!;
  return {
    readFile: (path) => api.readFile(path),
    readFileBuffer: async (path) => {
      const b64 = await api.readFileBuffer(path);
      const binary = atob(b64);
      const bytes = new Uint8Array(binary.length);
      for (let i = 0; i < binary.length; i++) {
        bytes[i] = binary.charCodeAt(i);
      }
      return bytes.buffer;
    },
    writeFile: (path, content) => api.writeFile(path, content),
    deleteFile: (path) => api.deleteFile(path),
    readDir: (path) => api.readDir(path) as Promise<FileEntry[]>,
    createDir: (path) => api.createDir(path),
    deleteDir: (path, recursive) => api.deleteDir(path, recursive),
    exists: (path) => api.exists(path),
    stat: (path) => api.stat(path) as Promise<FileEntry>,
    rename: (oldPath, newPath) => api.rename(oldPath, newPath),
    openFolderPath: (path) => api.openFolderPath(path),
    openFolder: () => api.openFolder(),
    openFile: () => api.openFile(),
    saveFileAs: (path, content) => api.saveFile(path, content),
    browseFilesystem: async () => ({ path: '/', parent: '/', entries: [] }),
    getWorkspaceRoots: async () => [],
    openWorkspace: async (rootPath, _providerConfig, _lightweight) => ({
      workspaceId: `ws_${Date.now()}`,
      rootPath,
      rootName: rootPath.split(/[\\/]/).pop() || rootPath,
      openTabs: [],
      createdAt: Date.now(),
      lastOpenedAt: Date.now(),
    }),
    closeWorkspace: async () => {},
    updateWorkspace: async () => {},
    getWorkspaceSessions: async () => [],
    saveWorkspaceSession: async () => {},
    deleteWorkspaceSession: async () => {},
  };
}

/** 创建 Server HTTP 客户端 —— 通过 fetch 调用 REST API */
export function createServerClient(baseUrl = ''): FileServiceClient {
  let workspaceRoot = '';

  async function request<T>(endpoint: string, options?: RequestInit): Promise<T> {
    const res = await fetch(`${baseUrl}${endpoint}`, {
      ...options,
      headers: { 'Content-Type': 'application/json', ...options?.headers },
    });
    if (!res.ok) throw new Error(`API error: ${res.status} ${res.statusText}`);
    return res.json();
  }

  function rootParam(root?: string): string {
    const r = root || workspaceRoot;
    return r ? `&root=${encodeURIComponent(r)}` : '';
  }

  return {
    readFile: async (path) => {
      const data = await request<{ content: string }>(`/api/files/read?path=${encodeURIComponent(path)}${rootParam()}`);
      return data.content;
    },
    readFileBuffer: async (path) => {
      const data = await request<{ path: string; data: string }>(
        `/api/files/read-buffer?path=${encodeURIComponent(path)}${rootParam()}`
      );
      const binary = atob(data.data);
      const bytes = new Uint8Array(binary.length);
      for (let i = 0; i < binary.length; i++) {
        bytes[i] = binary.charCodeAt(i);
      }
      return bytes.buffer;
    },
    writeFile: async (path, content) => {
      await request('/api/files/write', {
        method: 'POST',
        body: JSON.stringify({ path, content, root: workspaceRoot || undefined }),
      });
    },
    deleteFile: async (path) => {
      await request(`/api/files/delete?path=${encodeURIComponent(path)}${rootParam()}`, { method: 'DELETE' });
    },
    readDir: (path) => request<FileEntry[]>(`/api/files/list?path=${encodeURIComponent(path)}${rootParam()}`),
    createDir: async (path) => {
      await request('/api/files/mkdir', {
        method: 'POST',
        body: JSON.stringify({ path, root: workspaceRoot || undefined }),
      });
    },
    deleteDir: async (path, recursive = true) => {
      await request(`/api/files/rmdir?path=${encodeURIComponent(path)}&recursive=${recursive}${rootParam()}`, { method: 'DELETE' });
    },
    exists: async (path) => {
      const data = await request<{ exists: boolean }>(`/api/files/exists?path=${encodeURIComponent(path)}${rootParam()}`);
      return data.exists;
    },
    stat: (path) => request<FileEntry>(`/api/files/stat?path=${encodeURIComponent(path)}${rootParam()}`),
    rename: async (oldPath, newPath) => {
      await request('/api/files/rename', {
        method: 'POST',
        body: JSON.stringify({ oldPath, newPath, root: workspaceRoot || undefined }),
      });
    },
    openFolder: async () => null,
    openFile: async () => null,
    saveFileAs: async (filePath: string, content: string) => {
      try {
        await request('/api/files/write', {
          method: 'POST',
          body: JSON.stringify({ path: filePath, content, root: workspaceRoot || undefined }),
        });
        return filePath;
      } catch {
        return null;
      }
    },
    browseFilesystem: (path) => request(`/api/workspace/browse?path=${encodeURIComponent(path)}`),
    getWorkspaceRoots: () => request('/api/workspace/roots'),
    openWorkspace: async (rootPath, providerConfig, lightweight) => {
      return request('/api/workspace/open', {
        method: 'POST',
        body: JSON.stringify({ rootPath, providerConfig, lightweight }),
      });
    },
    closeWorkspace: async (workspaceId) => {
      await request('/api/workspace/close', {
        method: 'POST',
        body: JSON.stringify({ workspaceId }),
      });
    },
    updateWorkspace: async (workspaceId, data) => {
      await request('/api/workspace/update', {
        method: 'POST',
        body: JSON.stringify({ workspaceId, ...data }),
      });
    },
    getWorkspaceSessions: async (workspaceId) => {
      const data = await request<{ sessions: WorkspaceAgentSession[] }>(
        `/api/workspace/sessions?workspaceId=${encodeURIComponent(workspaceId)}`
      );
      return data.sessions;
    },
    saveWorkspaceSession: async (workspaceId, session) => {
      await request('/api/workspace/sessions', {
        method: 'POST',
        body: JSON.stringify({ workspaceId, session }),
      });
    },
    deleteWorkspaceSession: async (workspaceId, sessionId) => {
      await request(
        `/api/workspace/sessions/${encodeURIComponent(sessionId)}?workspaceId=${encodeURIComponent(workspaceId)}`,
        { method: 'DELETE' }
      );
    },
    setWorkspaceRoot: (root: string) => {
      workspaceRoot = root;
    },
  };
}

/**
 * 通过 FileSystemDirectoryHandle 按相对路径解析到目标 handle
 *
 * 逐级调用 getDirectoryHandle / getFileHandle 查找。
 * 返回 null 表示路径不存在。
 */
async function resolvePathFromHandle(
  rootHandle: FileSystemDirectoryHandle,
  relativePath: string
): Promise<FileSystemHandle | null> {
  const parts = relativePath.replace(/\\/g, '/').split('/').filter(Boolean);
  if (parts.length === 0) return rootHandle;

  let current: FileSystemDirectoryHandle = rootHandle;
  for (let i = 0; i < parts.length - 1; i++) {
    try {
      current = await current.getDirectoryHandle(parts[i]);
    } catch {
      return null;
    }
  }

  const lastName = parts[parts.length - 1];
  try {
    return await current.getDirectoryHandle(lastName);
  } catch {
    try {
      return await current.getFileHandle(lastName);
    } catch {
      return null;
    }
  }
}

/**
 * 解析到目标路径的父目录 handle 和名称
 *
 * 用于 writeFile / deleteFile 等需要先定位父目录再操作目标文件的场景。
 */
async function resolveParentHandle(
  rootHandle: FileSystemDirectoryHandle,
  relativePath: string
): Promise<{ parent: FileSystemDirectoryHandle; name: string } | null> {
  const parts = relativePath.replace(/\\/g, '/').split('/').filter(Boolean);
  if (parts.length === 0) return null;

  let parent: FileSystemDirectoryHandle = rootHandle;
  for (let i = 0; i < parts.length - 1; i++) {
    try {
      parent = await parent.getDirectoryHandle(parts[i]);
    } catch {
      return null;
    }
  }
  return { parent, name: parts[parts.length - 1] };
}

/** 目录缓存条目 */
interface DirCacheEntry {
  entries: FileEntry[];
  timestamp: number;
}

/**
 * 创建浏览器本地文件系统客户端
 *
 * 基于 File System Access API（showDirectoryPicker）实现。
 * 包含 2 秒 TTL 的目录缓存，减少频繁 readDir 调用。
 */
export function createBrowserLocalClient(rootHandle: FileSystemDirectoryHandle): FileServiceClient {
  const rootName = rootHandle.name;
  const dirCache = new Map<string, DirCacheEntry>();
  const CACHE_TTL = 2000;

  function cacheKey(p: string): string {
    return p.replace(/\\/g, '/').replace(/\/$/, '') || '.';
  }

  function normPath(p: string): string {
    const n = p.replace(/\\/g, '/');
    return n === '.' || n === '' ? '.' : n;
  }

  function fullPath(rel: string): string {
    const n = normPath(rel);
    return n === '.' ? rootName : `${rootName}/${n}`;
  }

  return {
    rootName,
    readFile: async (filePath: string) => {
      const handle = await resolvePathFromHandle(rootHandle, normPath(filePath));
      if (!handle || handle.kind !== 'file') throw new Error(`${i18n.global.t('errors.fileNotFound')} ${filePath}`);
      const file = await (handle as FileSystemFileHandle).getFile();
      return file.text();
    },

    readFileBuffer: async (filePath: string) => {
      const handle = await resolvePathFromHandle(rootHandle, normPath(filePath));
      if (!handle || handle.kind !== 'file') throw new Error(`${i18n.global.t('errors.fileNotFound')} ${filePath}`);
      const file = await (handle as FileSystemFileHandle).getFile();
      return file.arrayBuffer();
    },

    writeFile: async (filePath: string, content: string) => {
      const resolved = await resolveParentHandle(rootHandle, normPath(filePath));
      if (!resolved) throw new Error(`${i18n.global.t('errors.invalidPath')} ${filePath}`);
      const handle = await resolved.parent.getFileHandle(resolved.name, { create: true });
      const writable = await handle.createWritable();
      await writable.write(content);
      await writable.close();
      // 写入后清除父目录缓存
      dirCache.delete(cacheKey(normPath(filePath).replace(/\/[^/]+$/, '')));
    },

    deleteFile: async (filePath: string) => {
      const resolved = await resolveParentHandle(rootHandle, normPath(filePath));
      if (!resolved) throw new Error(`${i18n.global.t('errors.invalidPath')} ${filePath}`);
      await resolved.parent.removeEntry(resolved.name);
      dirCache.delete(cacheKey(normPath(filePath).replace(/\/[^/]+$/, '')));
    },

    readDir: async (dirPath: string) => {
      const key = cacheKey(dirPath);
      const cached = dirCache.get(key);
      // 缓存命中且未过期，直接返回
      if (cached && Date.now() - cached.timestamp < CACHE_TTL) return cached.entries;

      let dirHandle: FileSystemDirectoryHandle;
      if (dirPath === '.' || dirPath === '') {
        dirHandle = rootHandle;
      } else {
        const handle = await resolvePathFromHandle(rootHandle, normPath(dirPath));
        if (!handle || handle.kind !== 'directory') throw new Error(`${i18n.global.t('errors.dirNotFound')} ${dirPath}`);
        dirHandle = handle as FileSystemDirectoryHandle;
      }

      const entries: FileEntry[] = [];
      for await (const entry of (dirHandle as any).values()) {
        const entryName: string = entry.name;
        const isDir: boolean = entry.kind === 'directory';
        const entryPath = dirPath === '.' ? entryName : `${normPath(dirPath)}/${entryName}`;
        const fileEntry: FileEntry = {
          name: entryName,
          path: entryPath,
          isDirectory: isDir,
        };
        if (!isDir) {
          try {
            const file = await (entry as FileSystemFileHandle).getFile();
            fileEntry.size = file.size;
            fileEntry.modifiedAt = file.lastModified;
          } catch { /* 忽略获取文件元数据失败 */ }
        }
        entries.push(fileEntry);
      }

      // 目录优先，同类型按名称字母序排列
      entries.sort((a, b) => {
        if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
        return a.name.localeCompare(b.name);
      });

      dirCache.set(key, { entries, timestamp: Date.now() });
      return entries;
    },

    createDir: async (dirPath: string) => {
      const parts = normPath(dirPath).split('/').filter(Boolean);
      let current = rootHandle;
      for (const part of parts) {
        current = await current.getDirectoryHandle(part, { create: true });
      }
      dirCache.delete(cacheKey(dirPath));
    },

    deleteDir: async (dirPath: string, recursive = true) => {
      const resolved = await resolveParentHandle(rootHandle, normPath(dirPath));
      if (!resolved) throw new Error(`${i18n.global.t('errors.invalidPath')} ${dirPath}`);
      await resolved.parent.removeEntry(resolved.name, { recursive });
      dirCache.delete(cacheKey(dirPath));
    },

    exists: async (filePath: string) => {
      const handle = await resolvePathFromHandle(rootHandle, normPath(filePath));
      return handle !== null;
    },

    stat: async (filePath: string) => {
      const handle = await resolvePathFromHandle(rootHandle, normPath(filePath));
      if (!handle) throw new Error(`${i18n.global.t('errors.pathNotFound')} ${filePath}`);

      if (handle.kind === 'file') {
        const file = await (handle as FileSystemFileHandle).getFile();
        return {
          name: handle.name,
          path: fullPath(normPath(filePath)),
          isDirectory: false,
          size: file.size,
          modifiedAt: file.lastModified,
        };
      }
      return {
        name: handle.name,
        path: fullPath(normPath(filePath)),
        isDirectory: true,
      };
    },

    rename: async (oldPath: string, newPath: string) => {
      // 读取源文件内容
      const content = await (async () => {
        const handle = await resolvePathFromHandle(rootHandle, normPath(oldPath));
        if (!handle) throw new Error(`${i18n.global.t('errors.sourceNotFound')} ${oldPath}`);
        if (handle.kind === 'file') {
          return (handle as FileSystemFileHandle).getFile().then(f => f.text());
        }
        return '';
      })();

      const oldResolved = await resolveParentHandle(rootHandle, normPath(oldPath));
      if (!oldResolved) throw new Error(`${i18n.global.t('errors.sourceNotFound')} ${oldPath}`);

      const isDir = (await resolvePathFromHandle(rootHandle, normPath(oldPath)))?.kind === 'directory';

      if (isDir) {
        // 目录重命名：先收集子条目，删除旧目录，在新位置重建
        const newResolved = await resolveParentHandle(rootHandle, normPath(newPath));
        if (!newResolved) throw new Error(`${i18n.global.t('errors.invalidTarget')} ${newPath}`);

        const entries: FileEntry[] = [];
        const dirHandle = await oldResolved.parent.getDirectoryHandle(oldResolved.name);
        for await (const entry of (dirHandle as any).values()) {
          entries.push({ name: entry.name, path: '', isDirectory: entry.kind === 'directory' });
        }
        await oldResolved.parent.removeEntry(oldResolved.name, { recursive: true });

        dirCache.delete(cacheKey(oldPath));
        dirCache.delete(cacheKey(newPath));
      } else if (content !== undefined) {
        // 文件重命名：删除旧文件，在新位置创建并写入内容
        await oldResolved.parent.removeEntry(oldResolved.name);
        const newResolved = await resolveParentHandle(rootHandle, normPath(newPath));
        if (!newResolved) throw new Error(`${i18n.global.t('errors.invalidTarget')} ${newPath}`);
        const newHandle = await newResolved.parent.getFileHandle(newResolved.name, { create: true });
        const writable = await newHandle.createWritable();
        await writable.write(content);
        await writable.close();
        dirCache.delete(cacheKey(oldPath));
        dirCache.delete(cacheKey(newPath));
      }
    },

    openFolder: async () => null,
    openFile: async () => null,
    browseFilesystem: async () => ({ path: '/', parent: '/', entries: [] }),
    getWorkspaceRoots: async () => [],
    openWorkspace: async () => ({ workspaceId: '', rootPath: '', rootName: '', openTabs: [], createdAt: 0, lastOpenedAt: 0 }),
    closeWorkspace: async () => {},
    updateWorkspace: async () => {},
    getWorkspaceSessions: async () => [],
    saveWorkspaceSession: async () => {},
    deleteWorkspaceSession: async () => {},
  };
}

/** 根据当前环境自动创建对应的 FileServiceClient */
export function createFileServiceClient(): FileServiceClient {
  const env = detectEnvironment();
  if (env === 'electron') return createElectronClient();
  return createServerClient();
}

export function createBrowserLocalServiceClient(): FileServiceClient | null {
  if (detectEnvironment() !== 'browser') return null;
  return null;
}

/** 打开浏览器原生文件夹选择器，返回对应的 FileServiceClient */
export async function pickLocalFolder(): Promise<FileServiceClient | null> {
  try {
    const dirHandle = await showDirectoryPicker({ mode: 'readwrite' });
    return createBrowserLocalClient(dirHandle);
  } catch {
    return null;
  }
}

/** 打开浏览器原生文件选择器，返回文件路径和 File 对象 */
export async function pickLocalFile(): Promise<{ path: string; file: File } | null> {
  try {
    const [fileHandle] = await showOpenFilePicker({ multiple: false });
    const file = await fileHandle.getFile();
    return { path: file.name, file };
  } catch {
    return null;
  }
}
