/**
 * File Store for LocalGreenChain
 * Agent 3: File Upload & Storage System
 *
 * In-memory file metadata store (to be replaced with Prisma when Agent 2 completes)
 *
 * Prisma Schema (for Agent 2 to integrate):
 *
 * model File {
 *   id            String    @id @default(cuid())
 *   filename      String    // Storage path/key
 *   originalName  String    // Original uploaded filename
 *   mimeType      String
 *   size          Int       // File size in bytes
 *   category      String    // plant-photo, certificate, document, report, avatar
 *   url           String    // Public URL
 *   thumbnailUrl  String?   // Thumbnail URL (for images)
 *   urls          Json?     // All size variants URLs
 *   width         Int?      // Image width
 *   height        Int?      // Image height
 *   exifData      Json?     // EXIF metadata
 *   uploadedById  String?   // User who uploaded
 *   plantId       String?   // Associated plant
 *   farmId        String?   // Associated farm
 *   createdAt     DateTime  @default(now())
 *   updatedAt     DateTime  @updatedAt
 *   deletedAt     DateTime? // Soft delete
 *
 *   uploadedBy    User?     @relation(fields: [uploadedById], references: [id])
 *   plant         Plant?    @relation(fields: [plantId], references: [id])
 *   farm          VerticalFarm? @relation(fields: [farmId], references: [id])
 *
 *   @@index([category])
 *   @@index([plantId])
 *   @@index([farmId])
 *   @@index([uploadedById])
 * }
 */

import { FileMetadata, FileCategory, ImageSize } from './types';

/**
 * In-memory file store
 * This is a temporary implementation until Prisma is set up by Agent 2
 */
class FileStore {
  private files: Map<string, FileMetadata> = new Map();

  /**
   * Save file metadata
   */
  async save(metadata: FileMetadata): Promise<FileMetadata> {
    this.files.set(metadata.id, {
      ...metadata,
      updatedAt: new Date(),
    });
    return metadata;
  }

  /**
   * Get file by ID
   */
  async getById(id: string): Promise<FileMetadata | null> {
    const file = this.files.get(id);
    if (!file || file.deletedAt) {
      return null;
    }
    return file;
  }

  /**
   * Get file by filename/key
   */
  async getByFilename(filename: string): Promise<FileMetadata | null> {
    for (const file of this.files.values()) {
      if (file.filename === filename && !file.deletedAt) {
        return file;
      }
    }
    return null;
  }

  /**
   * Get files by plant ID
   */
  async getByPlantId(plantId: string): Promise<FileMetadata[]> {
    const results: FileMetadata[] = [];
    for (const file of this.files.values()) {
      if (file.plantId === plantId && !file.deletedAt) {
        results.push(file);
      }
    }
    return results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
  }

  /**
   * Get files by farm ID
   */
  async getByFarmId(farmId: string): Promise<FileMetadata[]> {
    const results: FileMetadata[] = [];
    for (const file of this.files.values()) {
      if (file.farmId === farmId && !file.deletedAt) {
        results.push(file);
      }
    }
    return results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
  }

  /**
   * Get files by user ID
   */
  async getByUserId(userId: string): Promise<FileMetadata[]> {
    const results: FileMetadata[] = [];
    for (const file of this.files.values()) {
      if (file.uploadedBy === userId && !file.deletedAt) {
        results.push(file);
      }
    }
    return results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
  }

  /**
   * Get files by category
   */
  async getByCategory(category: FileCategory): Promise<FileMetadata[]> {
    const results: FileMetadata[] = [];
    for (const file of this.files.values()) {
      if (file.category === category && !file.deletedAt) {
        results.push(file);
      }
    }
    return results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
  }

  /**
   * Update file metadata
   */
  async update(id: string, updates: Partial<FileMetadata>): Promise<FileMetadata | null> {
    const existing = this.files.get(id);
    if (!existing) {
      return null;
    }

    const updated: FileMetadata = {
      ...existing,
      ...updates,
      id, // Ensure ID cannot be changed
      updatedAt: new Date(),
    };

    this.files.set(id, updated);
    return updated;
  }

  /**
   * Soft delete a file
   */
  async softDelete(id: string): Promise<boolean> {
    const existing = this.files.get(id);
    if (!existing) {
      return false;
    }

    this.files.set(id, {
      ...existing,
      deletedAt: new Date(),
      updatedAt: new Date(),
    });
    return true;
  }

  /**
   * Hard delete a file
   */
  async hardDelete(id: string): Promise<boolean> {
    return this.files.delete(id);
  }

  /**
   * List all files with pagination
   */
  async list(options: {
    limit?: number;
    offset?: number;
    includeDeleted?: boolean;
  } = {}): Promise<{ files: FileMetadata[]; total: number }> {
    const { limit = 50, offset = 0, includeDeleted = false } = options;

    let results = Array.from(this.files.values());

    if (!includeDeleted) {
      results = results.filter((f) => !f.deletedAt);
    }

    // Sort by creation date descending
    results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());

    const total = results.length;
    const files = results.slice(offset, offset + limit);

    return { files, total };
  }

  /**
   * Get storage statistics
   */
  async getStats(): Promise<{
    totalFiles: number;
    totalSize: number;
    byCategory: Record<FileCategory, { count: number; size: number }>;
  }> {
    const stats: {
      totalFiles: number;
      totalSize: number;
      byCategory: Record<FileCategory, { count: number; size: number }>;
    } = {
      totalFiles: 0,
      totalSize: 0,
      byCategory: {
        'plant-photo': { count: 0, size: 0 },
        'certificate': { count: 0, size: 0 },
        'document': { count: 0, size: 0 },
        'report': { count: 0, size: 0 },
        'avatar': { count: 0, size: 0 },
      },
    };

    for (const file of this.files.values()) {
      if (!file.deletedAt) {
        stats.totalFiles++;
        stats.totalSize += file.size;
        stats.byCategory[file.category].count++;
        stats.byCategory[file.category].size += file.size;
      }
    }

    return stats;
  }

  /**
   * Clear all files (for testing)
   */
  clear(): void {
    this.files.clear();
  }
}

// Singleton instance
let fileStoreInstance: FileStore | null = null;

export function getFileStore(): FileStore {
  if (!fileStoreInstance) {
    fileStoreInstance = new FileStore();
  }
  return fileStoreInstance;
}

export { FileStore };
