const Minio = require('minio');
const crypto = require('crypto');

const getTrimmedEnv = (name, fallback = '') => String(process.env[name] ?? fallback).trim();

const MINIO_ENDPOINT = getTrimmedEnv('MINIO_ENDPOINT');
const MINIO_PORT = Number(process.env.MINIO_PORT || 9000);
const MINIO_USE_SSL = process.env.MINIO_USE_SSL === 'true';
const MINIO_ACCESS_KEY = getTrimmedEnv('MINIO_ACCESS_KEY');
const MINIO_SECRET_KEY = getTrimmedEnv('MINIO_SECRET_KEY');
const MINIO_BUCKET = getTrimmedEnv('MINIO_BUCKET', 'plant-images') || 'plant-images';

const isStorageConfigured = () => Boolean(MINIO_ENDPOINT && MINIO_ACCESS_KEY && MINIO_SECRET_KEY);

const getMinioPublicUrl = () =>
  getTrimmedEnv('MINIO_PUBLIC_URL', `http://${MINIO_ENDPOINT}:${MINIO_PORT}`).replace(/\/$/, '');

const getClient = () => {
  if (!isStorageConfigured()) {
    throw new Error('Image storage is not configured.');
  }

  return new Minio.Client({
    endPoint: MINIO_ENDPOINT,
    port: MINIO_PORT,
    useSSL: MINIO_USE_SSL,
    accessKey: MINIO_ACCESS_KEY,
    secretKey: MINIO_SECRET_KEY,
  });
};

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const ensureStorageBucket = async () => {
  const client = getClient();
  const exists = await client.bucketExists(MINIO_BUCKET);
  if (!exists) {
    await client.makeBucket(MINIO_BUCKET);
    const policy = JSON.stringify({
      Version: '2012-10-17',
      Statement: [
        {
          Effect: 'Allow',
          Principal: { AWS: ['*'] },
          Action: ['s3:GetObject'],
          Resource: [`arn:aws:s3:::${MINIO_BUCKET}/*`],
        },
      ],
    });
    await client.setBucketPolicy(MINIO_BUCKET, policy);
    console.log(`MinIO bucket '${MINIO_BUCKET}' created with public read policy.`);
  }
};

const ensureStorageBucketWithRetry = async (options = {}) => {
  const attempts = Number(options.attempts || 5);
  const delayMs = Number(options.delayMs || 2000);

  let lastError;
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
    try {
      await ensureStorageBucket();
      return;
    } catch (error) {
      lastError = error;
      if (attempt === attempts) break;
      console.warn(
        `MinIO bucket setup attempt ${attempt}/${attempts} failed: ${error.message}. Retrying in ${delayMs}ms...`,
      );
      await sleep(delayMs);
    }
  }

  throw lastError;
};

const uploadImage = async (base64Data, contentType = 'image/jpeg') => {
  const client = getClient();
  const rawExtension = contentType.split('/')[1] || 'jpg';
  const extension = rawExtension === 'jpeg' ? 'jpg' : rawExtension;
  const filename = `${Date.now()}-${crypto.randomBytes(8).toString('hex')}.${extension}`;
  const buffer = Buffer.from(base64Data, 'base64');

  await client.putObject(MINIO_BUCKET, filename, buffer, buffer.length, {
    'Content-Type': contentType,
  });

  const url = `${getMinioPublicUrl()}/${MINIO_BUCKET}/${filename}`;
  return { url, filename };
};

module.exports = {
  ensureStorageBucket,
  ensureStorageBucketWithRetry,
  uploadImage,
  isStorageConfigured,
};
