import { useClient, getHeaders } from 'hooks/useClient';

const API_URL = '/api';

export const useFilesAPI = (root: string = 'home') => {
  const client = useClient();
  const rootParam = root !== 'home' ? `root=${encodeURIComponent(root)}` : '';
  const withRoot = (url: string) =>
    rootParam ? (url.includes('?') ? `${url}&${rootParam}` : `${url}?${rootParam}`) : url;

  return {
    listDir: (path: string) =>
      client.get<ListDirResponse>(withRoot(`/file-browser/ls?path=${encodeURIComponent(path)}`)),

    createDir: (path: string) => client.post(withRoot('/file-browser/mkdir'), { path }),

    remove: (path: string) => client.delete(withRoot('/file-browser/rm'), { path }),

    rename: (path: string, newName: string) => client.post(withRoot('/file-browser/rename'), { path, newName }),

    readFile: (path: string) =>
      client.get<{ content: string; size: number }>(withRoot(`/file-browser/read?path=${encodeURIComponent(path)}`)),

    writeFile: (path: string, content: string) => client.post(withRoot('/file-browser/write'), { path, content }),

    search: (query: string, path?: string) =>
      client.get<{ results: DirEntry[] }>(
        withRoot(
          `/file-browser/search?q=${encodeURIComponent(query)}${path ? `&path=${encodeURIComponent(path)}` : ''}`,
        ),
      ),

    copy: (sources: string[], destination: string) =>
      client.post(withRoot('/file-browser/copy'), {
        items: sources.map((source) => ({
          source,
          destination: `${destination}/${source.split('/').pop()}`,
        })),
      }),

    move: (sources: string[], destination: string) =>
      client.post(withRoot('/file-browser/move'), {
        items: sources.map((source) => ({
          source,
          destination: `${destination}/${source.split('/').pop()}`,
        })),
      }),

    gitClone: (url: string, path: string) => client.post(withRoot('/file-browser/git-clone'), { url, path }),

    downloadVideo: (url: string, path: string, audioOnly: boolean) =>
      client.post<{ jobId: string }>(withRoot('/file-browser/download-video'), { url, path, audioOnly }),

    downloadVideoStatus: (jobId: string) =>
      client.get<DownloadVideoStatus>(withRoot(`/file-browser/download-video/${jobId}`)),

    // Prefetch one video's metadata (ReClip /api/info via the platform proxy). Returns { error } inline.
    videoInfo: (url: string) =>
      client.get<VideoInfo>(withRoot(`/file-browser/video-info?url=${encodeURIComponent(url)}`)),

    // Expand a playlist URL into its individual video URLs (ReClip /api/playlist).
    videoPlaylist: (url: string) =>
      client.get<{ urls?: string[]; error?: string }>(
        withRoot(`/file-browser/video-playlist?url=${encodeURIComponent(url)}`),
      ),

    tts: (path: string, opts?: { saveNextTo?: boolean }) =>
      client.post<{ audioPath: string; audioRoot: string }>('/file-browser/tts', { path, root, ...opts }),

    ttsText: (id: string, text: string) =>
      client.post<{ audioPath: string; audioRoot: string }>('/file-browser/tts-text', { id, text }),

    ocr: (path: string, opts?: { saveNextTo?: boolean }) =>
      client.post<{ ocrPath: string; ocrRoot: string }>('/file-browser/ocr', { path, root, ...opts }),

    transcribe: (path: string, opts?: { saveNextTo?: boolean }) =>
      client.post<{ transcriptionPath: string; transcriptionRoot: string }>('/file-browser/transcribe', {
        path,
        root,
        ...opts,
      }),

    extractAudio: (path: string) =>
      client.post<{ audioPath: string; audioRoot: string }>('/file-browser/extract-audio', { path, root }),

    extract: (path: string) => client.post<{ extractedPath: string }>('/file-browser/extract', { path, root }),

    saveResult: (path: string) => client.post<{ savedPath: string }>('/file-browser/save-result', { path }),

    audioTracks: (path: string) =>
      client.get<AudioTrack[]>(withRoot(`/file-browser/audio-tracks?path=${encodeURIComponent(path)}`)),

    audioMeta: (path: string) =>
      client.get<AudioMeta>(withRoot(`/file-browser/audio-meta?path=${encodeURIComponent(path)}`)),

    subtitles: (path: string) =>
      client.get<SubtitleTrack[]>(withRoot(`/file-browser/subtitles?path=${encodeURIComponent(path)}`)),

    probeFolder: (path: string) =>
      client.get<FolderProbe>(withRoot(`/file-browser/probe-folder?path=${encodeURIComponent(path)}`)),

    getRawUrl: (path: string) => {
      const token = getHeaders()['Authorization']?.replace('Bearer ', '') ?? '';
      const rp = root !== 'home' ? `&root=${encodeURIComponent(root)}` : '';
      return `${API_URL}/file-browser/raw?path=${encodeURIComponent(path)}&token=${encodeURIComponent(token)}${rp}`;
    },

    download: async (paths: string[]) => {
      if (paths.length === 1) {
        const blob = await client.getBlob(withRoot(`/file-browser/download?path=${encodeURIComponent(paths[0]!)}`));
        const name = paths[0]!.split('/').pop()!;
        const isDir = !name.includes('.') || blob.type === 'application/zip';
        triggerBlobDownload(blob, isDir && !name.endsWith('.zip') ? `${name}.zip` : name);
      } else {
        const headers = getHeaders();
        const url = `${API_URL}/${withRoot('/file-browser/download').replace(/^\//, '')}`;
        const res = await fetch(url, {
          method: 'POST',
          headers: { ...headers, 'Content-Type': 'application/json' },
          body: JSON.stringify({ paths }),
        });
        if (!res.ok) throw new Error('Download failed');
        const blob = await res.blob();
        triggerBlobDownload(blob, 'download.zip');
      }
    },

    uploadFiles: (path: string, files: FileList | File[], onProgress?: (pct: number) => void): Promise<void> => {
      const formData = new FormData();
      for (const file of Array.from(files)) {
        const name = (file as any).webkitRelativePath || file.name;
        formData.append('file', file, name);
      }
      const authHeaders = getHeaders();
      const url = withRoot(`${API_URL}/file-browser/upload?path=${encodeURIComponent(path)}`);

      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('POST', url);
        if (authHeaders['Authorization']) {
          xhr.setRequestHeader('Authorization', authHeaders['Authorization']);
        }
        xhr.upload.onprogress = (e) => {
          if (e.lengthComputable && onProgress) {
            onProgress(Math.round((e.loaded / e.total) * 100));
          }
        };
        xhr.onload = () => {
          if (xhr.status >= 400) reject(new Error(xhr.responseText));
          else resolve();
        };
        xhr.onerror = () => reject(new Error('Upload failed'));
        xhr.send(formData);
      });
    },
  };
};

export type UseFilesAPIType = ReturnType<typeof useFilesAPI>;

// ── Types ──

export type DownloadVideoStatus = {
  status: 'downloading' | 'transferring' | 'done' | 'error';
  error?: string;
  filename?: string;
};

export type VideoInfo = {
  title?: string;
  thumbnail?: string;
  duration?: number;
  uploader?: string;
  formats?: Array<{ height?: number; id?: string; label?: string }>; // present ⇒ video streams available
  error?: string;
};

export type AudioTrack = {
  id: number;
  codec: string;
  channels: number;
  bitrate: number | null;
  lang: string;
  title: string;
};
export type SubtitleTrack = { id: number; codec: string; lang: string; title: string };
export type AudioMeta = { title: string; artist: string; duration: number; hasLyrics: boolean };

export type FolderTrackGroup = {
  signature: string;
  count: number;
  files: string[];
  audioTracks: AudioTrack[];
  subtitleTracks: SubtitleTrack[];
};
export type FolderProbe = { fileCount: number; groups: FolderTrackGroup[] };

export type DirEntry = {
  name: string;
  path?: string;
  type: 'file' | 'directory';
  size: number;
  modifiedAt: number;
};

type ListDirResponse = {
  path: string;
  rootDir: string;
  entries: DirEntry[];
  reset?: boolean;
};

// ── Helpers ──

const triggerBlobDownload = (blob: Blob, filename: string) => {
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(a.href);
};
