import "server-only"

import { mkdir, readFile, writeFile, unlink, access } from "fs/promises"
import path from "path"

/**
 * Storage provider abstraction for file persistence.
 * Allows swapping local disk storage for cloud providers (OSS, S3) without
 * changing call sites.
 */
export interface StorageProvider {
  /** Persist a file buffer at the given relative path; returns the public URL. */
  save(file: Buffer, storagePath: string): Promise<string>
  /** Read a file buffer by its relative storage path. */
  read(storagePath: string): Promise<Buffer>
  /** Remove a file by its relative storage path. */
  delete(storagePath: string): Promise<void>
  /** Check whether a file exists at the relative storage path. */
  exists(storagePath: string): Promise<boolean>
  /** Resolve the public URL for a relative storage path. */
  getUrl(storagePath: string): string
}

/**
 * Local disk storage provider.
 * Files are persisted under `public/uploads/...` and served at `/uploads/...`.
 */
export class LocalStorageProvider implements StorageProvider {
  private readonly publicDir = path.join(process.cwd(), "public")

  async save(file: Buffer, storagePath: string): Promise<string> {
    const absolutePath = path.join(this.publicDir, storagePath)
    const dir = path.dirname(absolutePath)
    await mkdir(dir, { recursive: true })
    await writeFile(absolutePath, file)
    return this.getUrl(storagePath)
  }

  async read(storagePath: string): Promise<Buffer> {
    const absolutePath = path.join(this.publicDir, storagePath)
    return readFile(absolutePath)
  }

  async delete(storagePath: string): Promise<void> {
    const absolutePath = path.join(this.publicDir, storagePath)
    try {
      await unlink(absolutePath)
    } catch {
      // File may already be gone; ignore
    }
  }

  async exists(storagePath: string): Promise<boolean> {
    const absolutePath = path.join(this.publicDir, storagePath)
    try {
      await access(absolutePath)
      return true
    } catch {
      return false
    }
  }

  getUrl(storagePath: string): string {
    // Storage paths are relative to public/; URLs start with "/"
    if (storagePath.startsWith("/")) return storagePath
    return `/${storagePath}`
  }
}

/**
 * Default storage provider (local disk).
 * Swap this instance to migrate to OSS/S3 without touching call sites.
 */
export const storageProvider: StorageProvider = new LocalStorageProvider()
