import * as Minio from 'minio'

// MinIO client singleton
const globalForMinio = globalThis as unknown as {
  minio: Minio.Client | undefined
}

// Internal endpoint for server-to-server communication
const MINIO_ENDPOINT = process.env.MINIO_ENDPOINT || 'http://localhost:9000'

// Public endpoint for browser-accessible URLs (pre-signed URLs)
// If not set, falls back to internal endpoint
export const MINIO_PUBLIC_ENDPOINT = process.env.MINIO_PUBLIC_ENDPOINT || MINIO_ENDPOINT

function createMinioClient(): Minio.Client {
  const url = new URL(MINIO_ENDPOINT)

  return new Minio.Client({
    endPoint: url.hostname,
    port: url.port ? parseInt(url.port) : (url.protocol === 'https:' ? 443 : 80),
    useSSL: url.protocol === 'https:',
    accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',
    secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',
  })
}

export const minio = globalForMinio.minio ?? createMinioClient()

if (process.env.NODE_ENV !== 'production') globalForMinio.minio = minio

// Default bucket name
export const BUCKET_NAME = process.env.MINIO_BUCKET || 'mopc-files'

/**
 * Replace internal endpoint with public endpoint in a URL
 */
function replaceEndpoint(url: string): string {
  if (MINIO_PUBLIC_ENDPOINT === MINIO_ENDPOINT) {
    return url
  }

  try {
    const internalUrl = new URL(MINIO_ENDPOINT)
    const publicUrl = new URL(MINIO_PUBLIC_ENDPOINT)
    return url.replace(
      `${internalUrl.protocol}//${internalUrl.host}`,
      `${publicUrl.protocol}//${publicUrl.host}`
    )
  } catch {
    return url
  }
}

// =============================================================================
// Helper Functions
// =============================================================================

/**
 * Generate a pre-signed URL for file download or upload
 * Uses MINIO_PUBLIC_ENDPOINT for browser-accessible URLs
 */
export async function getPresignedUrl(
  bucket: string,
  objectKey: string,
  method: 'GET' | 'PUT' = 'GET',
  expirySeconds: number = 900 // 15 minutes default
): Promise<string> {
  let url: string
  if (method === 'GET') {
    url = await minio.presignedGetObject(bucket, objectKey, expirySeconds)
  } else {
    url = await minio.presignedPutObject(bucket, objectKey, expirySeconds)
  }

  // Replace internal endpoint with public endpoint for browser access
  return replaceEndpoint(url)
}

/**
 * Check if a bucket exists, create if not
 */
export async function ensureBucket(bucket: string): Promise<void> {
  const exists = await minio.bucketExists(bucket)
  if (!exists) {
    await minio.makeBucket(bucket)
    console.log(`Created MinIO bucket: ${bucket}`)
  }
}

/**
 * Delete an object from MinIO
 */
export async function deleteObject(
  bucket: string,
  objectKey: string
): Promise<void> {
  await minio.removeObject(bucket, objectKey)
}

/**
 * Generate a unique object key for a project file
 */
export function generateObjectKey(
  projectId: string,
  fileName: string
): string {
  const timestamp = Date.now()
  const sanitizedName = fileName.replace(/[^a-zA-Z0-9.-]/g, '_')
  return `projects/${projectId}/${timestamp}-${sanitizedName}`
}

/**
 * Get file metadata from MinIO
 */
export async function getObjectInfo(
  bucket: string,
  objectKey: string
): Promise<Minio.BucketItemStat> {
  return minio.statObject(bucket, objectKey)
}
