import { Client } from 'minio';
import type { BucketItem } from 'minio';

// Initialize MinIO client
export const getMinioClient = () => {
  const config = useRuntimeConfig().minio;
  
  return new Client({
    endPoint: config.endPoint,
    port: config.port,
    useSSL: config.useSSL,
    accessKey: config.accessKey,
    secretKey: config.secretKey,
  });
};

// File listing with metadata
export const listFiles = async (prefix: string = '', recursive: boolean = false) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  const files: any[] = [];
  const folders = new Set<string>();
  
  return new Promise(async (resolve, reject) => {
    try {
      const stream = client.listObjectsV2(bucketName, prefix, recursive);
      
      stream.on('data', (obj) => {
        // Handle folder prefixes returned by MinIO
        if (obj && obj.prefix) {
          folders.add(obj.prefix);
          return;
        }
        
        // Skip objects without a name
        if (!obj || typeof obj.name !== 'string') {
          return;
        }
        
        if (!recursive) {
          if (prefix) {
            // Extract folder structure when inside a folder
            const relativePath = obj.name.substring(prefix.length);
            if (!relativePath) return; // Skip if no relative path
            
            const firstSlash = relativePath.indexOf('/');
            
            if (firstSlash > -1) {
              // This is a folder
              const folderName = relativePath.substring(0, firstSlash);
              folders.add(prefix + folderName + '/');
            } else if (relativePath && !obj.name.endsWith('/')) {
              // This is a file in the current folder
              files.push({
                name: obj.name,
                size: obj.size || 0,
                lastModified: obj.lastModified || new Date(),
                etag: obj.etag || '',
                isFolder: false,
              });
            }
          } else {
            // At root level
            const firstSlash = obj.name.indexOf('/');
            
            if (obj.name.endsWith('/')) {
              // This is a folder placeholder created by createFolder
              folders.add(obj.name);
            } else if (firstSlash > -1) {
              // This is inside a folder, extract the folder
              const folderName = obj.name.substring(0, firstSlash);
              folders.add(folderName + '/');
            } else {
              // This is a file at root
              files.push({
                name: obj.name,
                size: obj.size || 0,
                lastModified: obj.lastModified || new Date(),
                etag: obj.etag || '',
                isFolder: false,
              });
            }
          }
        } else {
          // When recursive, include all files
          if (!obj.name.endsWith('/')) {
            files.push({
              name: obj.name,
              size: obj.size || 0,
              lastModified: obj.lastModified || new Date(),
              etag: obj.etag || '',
              isFolder: false,
            });
          }
        }
      });
      
      stream.on('error', (error) => {
        console.error('Stream error:', error);
        reject(error);
      });
      
      stream.on('end', () => {
        // Add folders to the result
        const folderItems = Array.from(folders).map(folder => ({
          name: folder,
          size: 0,
          lastModified: new Date(),
          etag: '',
          isFolder: true,
        }));
        
        resolve([...folderItems, ...files]);
      });
    } catch (error) {
      console.error('Error in listFiles:', error);
      reject(error);
    }
  });
};

// Upload file
export const uploadFile = async (filePath: string, fileBuffer: Buffer, contentType: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  return await client.putObject(bucketName, filePath, fileBuffer, fileBuffer.length, {
    'Content-Type': contentType,
  });
};

// Upload buffer (alias for uploadFile for compatibility)
export const uploadBuffer = async (buffer: Buffer, filePath: string, contentType: string) => {
  return uploadFile(filePath, buffer, contentType);
};

// Generate presigned URL for download
export const getDownloadUrl = async (fileName: string, expiry: number = 60 * 60) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  // Extract just the filename from the full path
  let filename = fileName.split('/').pop() || fileName;
  
  // Remove timestamp prefix if present (e.g., "1234567890-filename.pdf" -> "filename.pdf")
  const timestampMatch = filename.match(/^\d{10,}-(.+)$/);
  if (timestampMatch) {
    filename = timestampMatch[1];
  }
  
  // Force download with Content-Disposition header
  const responseHeaders = {
    'response-content-disposition': `attachment; filename="${filename}"`,
  };
  
  return await client.presignedGetObject(bucketName, fileName, expiry, responseHeaders);
};

// Delete file
export const deleteFile = async (fileName: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  return await client.removeObject(bucketName, fileName);
};

// Delete folder (recursively delete all contents)
export const deleteFolder = async (folderPath: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  // List all objects in the folder
  const objectsList: string[] = [];
  
  return new Promise((resolve, reject) => {
    const stream = client.listObjectsV2(bucketName, folderPath, true);
    
    stream.on('data', (obj) => {
      if (obj && obj.name) {
        objectsList.push(obj.name);
      }
    });
    
    stream.on('error', reject);
    
    stream.on('end', async () => {
      try {
        // Delete all objects
        if (objectsList.length > 0) {
          await client.removeObjects(bucketName, objectsList);
        }
        resolve(true);
      } catch (error) {
        reject(error);
      }
    });
  });
};

// Get file stats
export const getFileStats = async (fileName: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  return await client.statObject(bucketName, fileName);
};

// Create folder (MinIO doesn't have explicit folders, so we create a placeholder)
export const createFolder = async (folderPath: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  // Ensure folder path ends with /
  const normalizedPath = folderPath.endsWith('/') ? folderPath : folderPath + '/';
  
  // Create an empty object to represent the folder
  return await client.putObject(bucketName, normalizedPath, Buffer.from(''), 0);
};

// Get presigned URL for file preview
export const getPreviewUrl = async (fileName: string, contentType: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  // For images and PDFs, generate a presigned URL with appropriate response headers
  const responseHeaders = {
    'response-content-type': contentType,
    'response-content-disposition': 'inline',
  };
  
  return await client.presignedGetObject(bucketName, fileName, 60 * 60, responseHeaders);
};

// Rename file (copy and delete)
export const renameFile = async (oldPath: string, newPath: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  try {
    // Copy the object to the new name
    await client.copyObject(
      bucketName,
      newPath,
      `/${bucketName}/${oldPath}`
    );
    
    // Delete the old object
    await client.removeObject(bucketName, oldPath);
    
    return true;
  } catch (error) {
    console.error('Error renaming file:', error);
    throw error;
  }
};

// Rename folder (copy all contents and delete)
export const renameFolder = async (oldPath: string, newPath: string) => {
  const client = getMinioClient();
  const bucketName = useRuntimeConfig().minio.bucketName;
  
  // Ensure paths end with /
  const oldPrefix = oldPath.endsWith('/') ? oldPath : oldPath + '/';
  const newPrefix = newPath.endsWith('/') ? newPath : newPath + '/';
  
  // List all objects in the folder
  const objectsList: string[] = [];
  
  return new Promise((resolve, reject) => {
    const stream = client.listObjectsV2(bucketName, oldPrefix, true);
    
    stream.on('data', (obj) => {
      if (obj && obj.name) {
        objectsList.push(obj.name);
      }
    });
    
    stream.on('error', reject);
    
    stream.on('end', async () => {
      try {
        // Copy all objects to new location
        for (const objectName of objectsList) {
          const newObjectName = objectName.replace(oldPrefix, newPrefix);
          await client.copyObject(
            bucketName,
            newObjectName,
            `/${bucketName}/${objectName}`
          );
        }
        
        // Delete all old objects
        if (objectsList.length > 0) {
          await client.removeObjects(bucketName, objectsList);
        }
        
        resolve(true);
      } catch (error) {
        reject(error);
      }
    });
  });
};

// Create bucket if it doesn't exist
export const createBucketIfNotExists = async (bucketName?: string) => {
  const client = getMinioClient();
  const bucket = bucketName || useRuntimeConfig().minio.bucketName;
  
  try {
    const exists = await client.bucketExists(bucket);
    if (!exists) {
      await client.makeBucket(bucket);
      console.log(`Bucket '${bucket}' created successfully`);
    }
    return true;
  } catch (error) {
    console.error('Error creating bucket:', error);
    throw error;
  }
};
