// src/data-access/file-nodes.ts
import "server-only";

import { getOneDriveFileBuffer } from "@/services/onedrive";
import { extractMetadata } from "@/lib/metadata-extractor";
import { prisma } from "@/lib/prisma";


/**
 * FETCH: Retrieve all nodes for the dashboard.
 * Centralizing this here allows us to change sort order or filters 
 * in one place for the entire application.
 */
export async function getAllFileNodes() {
  return await prisma.fileNode.findMany({
    orderBy: {
      updatedAt: 'desc',
    },
  });
}

/**
 * FETCH: Get a single node by ID.
 * Used by the Download route and Update pages to verify a file exists.
 */
export async function getFileNodeById(id: string) {
  return await prisma.fileNode.findUnique({
    where: { id },
  });
}

/**
 * UPDATE: Modify metadata, name, or virtual location.
 * This function accepts the data object to keep the DAL flexible.
 */
export async function updateFileNode(id: string, data: any) {
  return await prisma.fileNode.update({
    where: { id },
    data: {
      ...data,
      updatedAt: new Date(),
    },
  });
}

/**
 * DELETE: Remove the record from the database.
 * Cloud deletion should be handled by the Service Layer before calling this.
 */
export async function deleteFileNode(id: string) {
  return await prisma.fileNode.delete({
    where: { id },
  });
}

/**
 * MASTER CREATE: Handles both standard uploads and virtual folders.
 * If no ID is provided, it generates a fresh UUID.
 */
export async function createFileNode(data: {
  id?: string;             // Optional: used for virtual folders/UUID storage
  oneDriveId: string | null;
  name: string;
  hash?: string | null;      // ✅ ADDED: For SHA-256 duplicate prevention
  description?: string;
  isFolder: boolean;
  path: string;
  ownerId: string;
  parentId?: string | null; // Optional: for nested structures
  size?: bigint;
  metadata: any;
}) {
  return await prisma.fileNode.create({
    data: {
      ...data,
      id: data.id ?? crypto.randomUUID(), // Use provided ID or generate new one
    }
  });
}


// ... other functions (getAllFileNodes, etc)

/**
 * UPSERT: Create or Update a file node based on OneDrive ID
 * Moved here because it interacts with the Database.
 */
export async function upsertFileNode(oneDriveId: string, data: {
  name: string;
  size: bigint;
  isFolder: boolean;
  path: string;
  ownerId: string;
  metadata: any;
  hash?: string | null;      // ✅ ADDED: Keep hash in sync during upserts
}) {
  return await prisma.fileNode.upsert({
    where: { oneDriveId },
    update: {
      name: data.name,
      size: data.size,
      isFolder: data.isFolder,
      path: data.path,
      hash: data.hash,       // ✅ ADDED
      updatedAt: new Date(),
    },
    create: {
      id: crypto.randomUUID(),
      oneDriveId: oneDriveId,
      name: data.name,
      size: data.size,
      isFolder: data.isFolder,
      path: data.path,
      ownerId: data.ownerId,
      metadata: data.metadata,
      hash: data.hash,       // ✅ ADDED
    }
  });
}

/**
 * FETCH: Get all virtual folders for selection in dropdowns.
 * Used by the BulkUpload page to set destinations.
 */
export async function getAllFolders() {
  return await prisma.fileNode.findMany({
    where: { 
      isFolder: true 
    },
    select: { 
      id: true, 
      name: true 
    },
    orderBy: { 
      name: 'asc' 
    }
  });
}

/**
 * UPSERT BY HASH: The core of the Disaster Recovery process.
 * If a hash exists, we update the OneDrive ID (Restoring the link).
 * If not, we create a new entry.
 */
export async function upsertFileNodeByHash(data: {
  name: string;
  hash: string;
  oneDriveId: string;
  parentId?: string | null;
  size: bigint;
  ownerId: string;
  mimeType?: string;
}) {
  // First, check if we have a record with this hash
  const existing = await prisma.fileNode.findFirst({
    where: { hash: data.hash }
  });

  if (existing) {
    // 🛡️ DISASTER RECOVERY MODE
    // The database knows about this file, but the OneDrive link is old.
    // We update the existing record with the NEW cloud ID.
    return await prisma.fileNode.update({
      where: { id: existing.id },
      data: {
        oneDriveId: data.oneDriveId,
        // Optional: Update parent if the user chose a new folder during restore
        parentId: data.parentId || existing.parentId,
        updatedAt: new Date(),
      }
    });
  }

  // ✨ NEW UPLOAD MODE
  return await prisma.fileNode.create({
    data: {
      id: crypto.randomUUID(),
      oneDriveId: data.oneDriveId,
      name: data.name,
      hash: data.hash,
      size: data.size,
      isFolder: false,
      ownerId: data.ownerId,
      parentId: data.parentId || null,
      path: data.name, // Simplified for now
      metadata: {},    // Placeholder for extractMetadata logic
    }
  });
}

