import { eq, and, isNull } from 'drizzle-orm'
import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'
import { storageFolders, storageFiles } from '../db/schema/storage.js'
import type { DavResource } from '../utils/webdav-xml.js'

interface ResolvedPath {
  type: 'root' | 'folder' | 'file' | null
  folder?: typeof storageFolders.$inferSelect
  file?: typeof storageFiles.$inferSelect
  parentFolder?: typeof storageFolders.$inferSelect
}

export const WebDavService = {
  /**
   * Resolve a WebDAV URL path to a database entity.
   * Path is relative to /webdav/ (e.g., "/HR Documents/Policies/handbook.pdf")
   */
  async resolvePath(db: PostgresJsDatabase<any>, urlPath: string): Promise<ResolvedPath> {
    const segments = urlPath.split('/').filter(Boolean).map(decodeURIComponent)

    // Reject path traversal and null bytes
    if (segments.some(s => s === '.' || s === '..' || s.includes('\0'))) {
      return { type: null }
    }

    if (segments.length === 0) {
      return { type: 'root' }
    }

    // Walk the folder tree
    let currentFolder: typeof storageFolders.$inferSelect | undefined
    let parentFolder: typeof storageFolders.$inferSelect | undefined

    for (let i = 0; i < segments.length; i++) {
      const segment = segments[i]
      const isLast = i === segments.length - 1
      const parentId = currentFolder?.id ?? null

      // Try to find a folder with this name under the current parent
      const whereClause = parentId
        ? and(eq(storageFolders.name, segment), eq(storageFolders.parentId, parentId))
        : and(eq(storageFolders.name, segment), isNull(storageFolders.parentId))

      const [folder] = await db.select().from(storageFolders).where(whereClause).limit(1)

      if (folder) {
        parentFolder = currentFolder
        currentFolder = folder
        continue
      }

      // Not a folder — if this is the last segment, check for a file
      if (isLast && currentFolder) {
        const [file] = await db.select().from(storageFiles)
          .where(and(eq(storageFiles.folderId, currentFolder.id), eq(storageFiles.filename, segment)))
          .limit(1)

        if (file) {
          return { type: 'file', file, folder: currentFolder, parentFolder }
        }
      }

      // Also check for a file at root level (no parent folder) - not supported in our model
      // Files must be in folders
      return { type: null }
    }

    return { type: 'folder', folder: currentFolder, parentFolder }
  },

  /**
   * List children of a folder (or root) as DAV resources.
   */
  async listChildren(db: PostgresJsDatabase<any>, folderId: string | null, basePath: string, foldersOnly = false): Promise<DavResource[]> {
    const resources: DavResource[] = []

    // Sub-folders
    const folderWhere = folderId
      ? eq(storageFolders.parentId, folderId)
      : isNull(storageFolders.parentId)
    const subFolders = await db.select().from(storageFolders).where(folderWhere).orderBy(storageFolders.name)

    for (const folder of subFolders) {
      resources.push({
        href: `${basePath}${encodeURIComponent(folder.name)}/`,
        isCollection: true,
        displayName: folder.name,
        lastModified: folder.updatedAt ? new Date(folder.updatedAt) : undefined,
        createdAt: folder.createdAt ? new Date(folder.createdAt) : undefined,
      })
    }

    // Files (only if we're inside a folder, not root, and not traverse-only)
    if (folderId && !foldersOnly) {
      const files = await db.select().from(storageFiles)
        .where(eq(storageFiles.folderId, folderId))
        .orderBy(storageFiles.filename)

      for (const file of files) {
        resources.push({
          href: `${basePath}${encodeURIComponent(file.filename)}`,
          isCollection: false,
          displayName: file.filename,
          contentType: file.contentType,
          contentLength: file.sizeBytes,
          lastModified: file.createdAt ? new Date(file.createdAt) : undefined,
          createdAt: file.createdAt ? new Date(file.createdAt) : undefined,
          etag: file.id,
        })
      }
    }

    return resources
  },

  /**
   * Parse the parent path and filename from a WebDAV path.
   */
  parseParentAndName(urlPath: string): { parentPath: string; name: string } {
    const segments = urlPath.split('/').filter(Boolean).map(decodeURIComponent)
    if (segments.length === 0) return { parentPath: '/', name: '' }
    const name = segments[segments.length - 1]
    const parentPath = '/' + segments.slice(0, -1).join('/')
    return { parentPath, name }
  },
}
