"use client"

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
import { apiClient } from "@/lib/api/client"
import { driveFilesListApiPath, driveFilterCorpusApiPath } from "@/lib/api/drive-download"
import {
  driveMountFilesApiPath,
  driveOrgFilesApiPath,
  type DrivePathRef,
  withMoveCopyRefs,
  withPathRefBody,
} from "@/lib/api/drive-roots"
import { useAuthReady } from "@/lib/api/use-auth-ready"
import { useDemoDrive, useIsDemoDrive } from "@/lib/demo/demo-drive-context"
import { DEMO_DRIVE_QUERY_ROOT } from "@/lib/demo/demo-drive-bootstrap"
import { useDemoDriveStore } from "@/lib/demo/demo-drive-store"
import type {
  DriveFileInfo,
  DriveListResponse,
  DriveMount,
  DriveOrgFolder,
  DriveQuota,
  DriveShare,
  ShareRecipientLookup,
} from "@/lib/api/types"
import type { DriveShareMode } from "@/lib/drive/drive-share-types"

function filesKey(path: string, page: number, q: string) {
  return ["drive", "files", path, page, q] as const
}

function demoFilesKey(path: string, page: number, q: string, version: number) {
  return [...DEMO_DRIVE_QUERY_ROOT, "files", path, page, q, version] as const
}

function filterCorpusKey(path: string) {
  return ["drive", "filter-corpus", path] as const
}

export function useDriveFilterCorpus(path: string, enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const apiPath = driveFilterCorpusApiPath(path)
  return useQuery({
    queryKey: filterCorpusKey(path),
    enabled: ready && authenticated && enabled,
    staleTime: 60_000,
    queryFn: () => apiClient.get<DriveListResponse>(apiPath),
  })
}

export function useDriveList(path: string, page = 1, q = "", enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  const apiPath = driveFilesListApiPath(path)
  return useQuery({
    queryKey: isDemoDrive
      ? demoFilesKey(path, page, q, demoVersion)
      : filesKey(path, page, q),
    enabled: ready && authenticated && enabled,
    queryFn: () => {
      if (isDemoDrive) {
        return useDemoDriveStore.getState().listFiles(path, page)
      }
      return apiClient.get<DriveListResponse>(
        `${apiPath}?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}`
      )
    },
    initialData: isDemoDrive
      ? () => useDemoDriveStore.getState().listFiles(path, page)
      : undefined,
  })
}

export function useDriveFileById(fileId: string, enabled = true) {
  const { ready, authenticated } = useAuthReady()
  return useQuery({
    queryKey: ["drive", "file", fileId],
    enabled: ready && authenticated && enabled && Boolean(fileId),
    staleTime: 30_000,
    queryFn: () => apiClient.get<DriveFileInfo>(`/drive/files/id/${encodeURIComponent(fileId)}`),
  })
}

export function useDriveSharedWithMe(page = 1, q = "", enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "shared", page, q, demoVersion]
      : ["drive", "shared", page, q],
    enabled: ready && authenticated && enabled,
    queryFn: () => {
      if (isDemoDrive) return useDemoDriveStore.getState().listShared()
      return apiClient.get<DriveListResponse>(
        `/drive/shared?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}`
      )
    },
    initialData: isDemoDrive
      ? () => useDemoDriveStore.getState().listShared()
      : undefined,
  })
}

export function useDriveTrash(page = 1, q = "") {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "trash", page, q, demoVersion]
      : ["drive", "trash", page, q],
    enabled: ready && authenticated,
    queryFn: () => {
      if (isDemoDrive) return useDemoDriveStore.getState().listTrash()
      return apiClient.get<DriveListResponse>(
        `/drive/trash?page=${page}&page_size=50${q ? `&q=${encodeURIComponent(q)}` : ""}`
      )
    },
    initialData: isDemoDrive
      ? () => useDemoDriveStore.getState().listTrash()
      : undefined,
  })
}

export function useDriveRecent() {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "recent", demoVersion]
      : ["drive", "recent"],
    enabled: ready && authenticated,
    retry: 1,
    queryFn: () => {
      if (isDemoDrive) return useDemoDriveStore.getState().listRecent()
      return apiClient.get<DriveListResponse>("/drive/recent?page_size=50")
    },
    initialData: isDemoDrive
      ? () => useDemoDriveStore.getState().listRecent()
      : undefined,
  })
}

export function useDriveStarred(path = "/") {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  const suffix = path === "/" ? "" : path
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "starred", path, demoVersion]
      : ["drive", "starred", path],
    enabled: ready && authenticated,
    queryFn: () => {
      if (isDemoDrive) return useDemoDriveStore.getState().listStarred(path)
      return apiClient.get<DriveListResponse>(`/drive/starred${suffix}?page_size=50`)
    },
    initialData: isDemoDrive
      ? () => useDemoDriveStore.getState().listStarred(path)
      : undefined,
  })
}

function searchKey(q: string, scope: string, path: string, page: number, suggest: boolean) {
  return ["drive", "search", q, scope, path, page, suggest] as const
}

export function useDriveSearch(
  q: string,
  scope: string,
  path: string,
  page = 1,
  enabled = true
) {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  const trimmed = q.trim()
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "search", trimmed, scope, path, page, false, demoVersion]
      : searchKey(trimmed, scope, path, page, false),
    enabled: ready && authenticated && enabled && trimmed.length > 0,
    queryFn: () => {
      if (isDemoDrive) {
        return useDemoDriveStore.getState().search(trimmed, scope, path, page)
      }
      const params = new URLSearchParams({
        q: trimmed,
        scope,
        page: String(page),
        page_size: "50",
      })
      if (scope === "folder" && path !== "/") {
        params.set("path", path)
      }
      return apiClient.get<DriveListResponse>(`/drive/search?${params.toString()}`)
    },
    initialData:
      isDemoDrive && trimmed.length > 0
        ? () => useDemoDriveStore.getState().search(trimmed, scope, path, page)
        : undefined,
  })
}

export function useDriveSearchSuggestions(
  q: string,
  scope: string,
  path: string,
  enabled = true
) {
  const { ready, authenticated } = useAuthReady()
  const isDemoDrive = useIsDemoDrive()
  const demoVersion = useDemoDriveStore((s) => s.version)
  const trimmed = q.trim()
  return useQuery({
    queryKey: isDemoDrive
      ? [...DEMO_DRIVE_QUERY_ROOT, "search", trimmed, scope, path, 1, true, demoVersion]
      : searchKey(trimmed, scope, path, 1, true),
    enabled: ready && authenticated && enabled && trimmed.length >= 2,
    staleTime: 30_000,
    queryFn: () => {
      if (isDemoDrive) {
        const res = useDemoDriveStore.getState().search(trimmed, scope, path, 1)
        return { ...res, files: res.files.slice(0, 8) }
      }
      const params = new URLSearchParams({
        q: trimmed,
        scope,
        suggest: "1",
        page_size: "8",
      })
      if (scope === "folder" && path !== "/") {
        params.set("path", path)
      }
      return apiClient.get<DriveListResponse>(`/drive/search?${params.toString()}`)
    },
    initialData:
      isDemoDrive && trimmed.length >= 2
        ? () => {
            const res = useDemoDriveStore.getState().search(trimmed, scope, path, 1)
            return { ...res, files: res.files.slice(0, 8) }
          }
        : undefined,
  })
}

export function useDriveQuota() {
  const { ready, authenticated } = useAuthReady()
  return useQuery({
    queryKey: ["drive", "quota"],
    enabled: ready && authenticated,
    retry: 1,
    queryFn: () => apiClient.get<DriveQuota>("/drive/quota"),
  })
}

export function useDriveShares(filePath: string, enabled: boolean, pathRef?: DrivePathRef) {
  const { ready, authenticated } = useAuthReady()
  const rootQs =
    pathRef?.root && pathRef.root !== "personal"
      ? `&root=${encodeURIComponent(pathRef.root)}&root_id=${encodeURIComponent(pathRef.root_id ?? "")}`
      : ""
  return useQuery({
    queryKey: ["drive", "shares", filePath, pathRef?.root, pathRef?.root_id],
    enabled: ready && authenticated && enabled && Boolean(filePath),
    queryFn: () =>
      apiClient.get<{ shares: DriveShare[] }>(
        `/drive/shares?path=${encodeURIComponent(filePath)}${rootQs}`
      ),
  })
}

export function useDriveOrgFolders(enabled = true) {
  const { ready, authenticated } = useAuthReady()
  return useQuery({
    queryKey: ["drive", "org-folders"],
    enabled: ready && authenticated && enabled,
    staleTime: 60_000,
    queryFn: async () => {
      const res = await apiClient.get<{ folders: DriveOrgFolder[] }>("/drive/org-folders")
      return res.folders ?? []
    },
  })
}

export function useDriveOrgList(folderId: string, path: string, page = 1, enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const apiPath = driveOrgFilesApiPath(folderId, path)
  return useQuery({
    queryKey: ["drive", "org", folderId, path, page],
    enabled: ready && authenticated && enabled && Boolean(folderId),
    queryFn: () =>
      apiClient.get<DriveListResponse>(`${apiPath}?page=${page}&page_size=50`),
  })
}

export function useDriveMounts(orgSlugs: string[] = [], enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const slugParam = orgSlugs.filter(Boolean).join(",")
  return useQuery({
    queryKey: ["drive", "mounts", slugParam],
    enabled: ready && authenticated && enabled,
    staleTime: 30_000,
    queryFn: async () => {
      const qs = slugParam ? `?org_slugs=${encodeURIComponent(slugParam)}` : ""
      const res = await apiClient.get<{ mounts: DriveMount[] }>(`/drive/mounts${qs}`)
      return res.mounts ?? []
    },
  })
}

export function useDriveMountList(mountId: string, path: string, page = 1, enabled = true) {
  const { ready, authenticated } = useAuthReady()
  const apiPath = driveMountFilesApiPath(mountId, path)
  return useQuery({
    queryKey: ["drive", "mount", mountId, path, page],
    enabled: ready && authenticated && enabled && Boolean(mountId),
    queryFn: () =>
      apiClient.get<DriveListResponse>(`${apiPath}?page=${page}&page_size=50`),
  })
}

export function useDriveMutations(pathRef?: DrivePathRef) {
  const qc = useQueryClient()
  const demoDrive = useDemoDrive()
  const isDemoDrive = demoDrive?.enabled ?? false
  const invalidate = () => {
    if (isDemoDrive) {
      useDemoDriveStore.getState().bump()
      void qc.invalidateQueries({ queryKey: DEMO_DRIVE_QUERY_ROOT })
      return
    }
    void qc.invalidateQueries({ queryKey: ["drive"] })
  }

  const ref = pathRef ?? { path: "/" }
  const rootPrefix =
    ref.root === "org" && ref.root_id
      ? `/drive/org-folders/${encodeURIComponent(ref.root_id)}`
      : ref.root === "mount" && ref.root_id
        ? `/drive/mounts/${encodeURIComponent(ref.root_id)}`
        : "/drive"

  const createFolder = useMutation({
    mutationFn: async (path: string) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().createFolder(path)
        return
      }
      if (ref.root === "org" || ref.root === "mount") {
        return apiClient.post<void>(`${rootPrefix}/folders${path}`, {})
      }
      return apiClient.post<void>(`/drive/folders${path}`, {})
    },
    onSuccess: invalidate,
  })
  const deleteFile = useMutation({
    mutationFn: async (path: string) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().deleteFile(path)
        demoDrive?.notify("Élément placé dans la corbeille")
        return
      }
      if (ref.root === "org" || ref.root === "mount") {
        return apiClient.delete(`${rootPrefix}/files${path}`)
      }
      return apiClient.delete(`/drive/files${path}`)
    },
    onSuccess: invalidate,
  })
  const rename = useMutation({
    mutationFn: async (body: { path: string; new_name: string }) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().rename(body.path, body.new_name)
        return
      }
      return apiClient.post<void>(
        "/drive/rename",
        withPathRefBody(body, { ...ref, path: body.path })
      )
    },
    onSuccess: invalidate,
  })
  const move = useMutation({
    mutationFn: (body: { source: string; destination: string; sourceRef?: DrivePathRef; destRef?: DrivePathRef }) =>
      apiClient.post<void>(
        "/drive/move",
        withMoveCopyRefs(
          body.sourceRef ?? { ...ref, path: body.source },
          body.destRef ?? { ...ref, path: body.destination }
        )
      ),
    onSuccess: invalidate,
  })
  const copy = useMutation({
    mutationFn: (body: { source: string; destination: string; sourceRef?: DrivePathRef; destRef?: DrivePathRef }) =>
      apiClient.post<void>(
        "/drive/copy",
        withMoveCopyRefs(
          body.sourceRef ?? { ...ref, path: body.source },
          body.destRef ?? { ...ref, path: body.destination }
        )
      ),
    onSuccess: invalidate,
  })
  const favorite = useMutation({
    mutationFn: async (body: { path: string; favorite: boolean }) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().setFavorite(body.path, body.favorite)
        return
      }
      return apiClient.post<void>(
        "/drive/favorite",
        withPathRefBody(body, { ...ref, path: body.path })
      )
    },
    onSuccess: invalidate,
  })
  const restore = useMutation({
    mutationFn: async (name: string) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().restoreTrash(name)
        return
      }
      return apiClient.post<void>("/drive/trash/restore", { name })
    },
    onSuccess: invalidate,
  })
  const deleteTrash = useMutation({
    mutationFn: async (name: string) => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().deleteTrash(name)
        return
      }
      return apiClient.post<void>("/drive/trash/delete", { name })
    },
    onSuccess: invalidate,
  })
  const emptyTrash = useMutation({
    mutationFn: async () => {
      if (isDemoDrive) {
        useDemoDriveStore.getState().emptyTrash()
        return
      }
      return apiClient.delete("/drive/trash")
    },
    onSuccess: invalidate,
  })
  const createShare = useMutation({
    mutationFn: (body: {
      path: string
      mode?: DriveShareMode
      role?: string
      permissions?: number
      share_type?: number
      share_with?: string
      note?: string
      send_mail?: boolean
    }) =>
      apiClient.post<DriveShare>("/drive/shares", {
        ...withPathRefBody({ path: body.path }, { ...ref, path: body.path }),
        mode: body.mode ?? "public",
        ...(body.mode === "contact"
          ? {
              share_with: body.share_with,
              note: body.note,
              send_mail: body.send_mail ?? true,
            }
          : body.mode === "internal"
            ? { share_type: 3 }
            : { share_type: body.share_type ?? 3 }),
        ...(body.permissions != null && body.permissions > 0
          ? { permissions: body.permissions }
          : { role: body.role ?? "viewer" }),
      }),
    onSuccess: (_data, variables) => {
      qc.invalidateQueries({ queryKey: ["drive"] })
      if (variables.path) {
        qc.invalidateQueries({ queryKey: ["drive", "shares", variables.path] })
      }
    },
  })
  const deleteShare = useMutation({
    mutationFn: (shareId: string) => apiClient.delete(`/drive/shares/${shareId}`),
    onSuccess: invalidate,
  })
  const lookupShareRecipient = useMutation({
    mutationFn: (email: string) =>
      apiClient.get<ShareRecipientLookup>(
        `/drive/shares/recipients/lookup?email=${encodeURIComponent(email)}`
      ),
  })
  const createFile = useMutation({
    mutationFn: (body: { parent_path: string; name: string; kind: string }) =>
      apiClient.post<{ path: string; file_id?: number }>("/drive/files/new", body),
    onSuccess: invalidate,
  })

  return { createFolder, deleteFile, rename, move, copy, favorite, restore, deleteTrash, emptyTrash, createShare, deleteShare, lookupShareRecipient, createFile, invalidate }
}

export function useDriveMountMutations() {
  const qc = useQueryClient()
  const invalidate = () => qc.invalidateQueries({ queryKey: ["drive", "mounts"] })

  const createMount = useMutation({
    mutationFn: (body: {
      scope: "user" | "org"
      org_slug?: string
      display_name: string
      backend_type: string
      webdav?: { host: string; root: string; user: string; password: string; secure?: boolean }
      oauth_backend?: string
      oauth_auth?: string
    }) => apiClient.post<DriveMount>("/drive/mounts", body),
    onSuccess: invalidate,
  })

  const deleteMount = useMutation({
    mutationFn: (mountId: string) => apiClient.delete(`/drive/mounts/${encodeURIComponent(mountId)}`),
    onSuccess: invalidate,
  })

  const fetchOAuthURL = async (mountId: string, redirectUri: string) =>
    apiClient.get<{ oauth_url: string }>(
      `/drive/mounts/${encodeURIComponent(mountId)}/oauth-url?redirect_uri=${encodeURIComponent(redirectUri)}`
    )

  const completeOAuth = useMutation({
    mutationFn: ({ mountId, code, redirectUri }: { mountId: string; code: string; redirectUri: string }) =>
      apiClient.post<{ status: string }>(`/drive/mounts/${encodeURIComponent(mountId)}/oauth/complete`, {
        code,
        redirect_uri: redirectUri,
      }),
    onSuccess: invalidate,
  })

  return { createMount, deleteMount, fetchOAuthURL, completeOAuth, invalidate }
}

/** @deprecated Use openDriveFileInNewTab / downloadDriveFile — API requires Authorization. */
export function fileDownloadUrl(path: string): string {
  const base = process.env.NEXT_PUBLIC_API_URL ?? "/api/v1"
  return `${base}/drive/download${path.startsWith("/") ? path : `/${path}`}`
}

export type { DriveFileInfo }
