import {
  DeleteObjectCommand,
  PutObjectCommand,
  S3Client,
} from '@aws-sdk/client-s3';

/**
 * MinIO / S3-compatible object storage (CT 102).
 *
 * Env:
 *   S3_ENDPOINT          — e.g. http://192.168.68.102:9000
 *   S3_ACCESS_KEY_ID     — app-scoped MinIO user
 *   S3_SECRET_ACCESS_KEY
 *   S3_BUCKET            — e.g. deckhearth
 *   S3_PUBLIC_BASE_URL   — e.g. https://cdn.stillwell.cloud/deckhearth
 *   S3_REGION            — optional, default us-east-1
 */

let client = null;

function requireEnv(name) {
  const value = process.env[name];
  if (!value?.trim()) {
    throw new Error(`${name} is not configured`);
  }
  return value.trim();
}

function getClient() {
  if (!client) {
    client = new S3Client({
      endpoint: requireEnv('S3_ENDPOINT'),
      region: process.env.S3_REGION || 'us-east-1',
      credentials: {
        accessKeyId: requireEnv('S3_ACCESS_KEY_ID'),
        secretAccessKey: requireEnv('S3_SECRET_ACCESS_KEY'),
      },
      forcePathStyle: true,
    });
  }
  return client;
}

function getBucket() {
  return requireEnv('S3_BUCKET');
}

function publicUrlForKey(key) {
  const base = requireEnv('S3_PUBLIC_BASE_URL').replace(/\/$/, '');
  return `${base}/${key.replace(/^\//, '')}`;
}

/** Extract object key from a stored public URL or pass through raw keys. */
export function objectKeyFromReference(reference) {
  if (!reference || typeof reference !== 'string') {
    throw new Error('Invalid object reference');
  }
  if (!reference.startsWith('http')) {
    return reference.replace(/^\//, '');
  }

  const base = process.env.S3_PUBLIC_BASE_URL?.replace(/\/$/, '');
  if (base && reference.startsWith(`${base}/`)) {
    return reference.slice(base.length + 1);
  }

  try {
    const url = new URL(reference);
    const parts = url.pathname.split('/').filter(Boolean);
    const bucket = getBucket();
    if (parts[0] === bucket) {
      return parts.slice(1).join('/');
    }
    return parts.join('/');
  } catch {
    throw new Error('Could not parse object URL for deletion');
  }
}

/**
 * Drop-in replacement for `@vercel/blob` put (access ignored — bucket policy controls visibility).
 * @returns {Promise<{ url: string }>}
 */
export async function put(key, body, { contentType } = {}) {
  const objectKey = key.replace(/^\//, '');
  await getClient().send(
    new PutObjectCommand({
      Bucket: getBucket(),
      Key: objectKey,
      Body: body,
      ContentType: contentType,
    })
  );
  return { url: publicUrlForKey(objectKey) };
}

/** Delete by object key or public URL (legacy blob URLs in DB). */
export async function del(urlOrKey) {
  const objectKey = objectKeyFromReference(urlOrKey);
  await getClient().send(
    new DeleteObjectCommand({
      Bucket: getBucket(),
      Key: objectKey,
    })
  );
}
