/**
 * MinIO storage helpers for ANCPI CF extracts.
 *
 * Bucket: ancpi-documente (separate from general "tools" bucket)
 * Naming: {index:02d}_Extras CF_{nrCadastral} - {DD-MM-YYYY}.pdf
 */

import { minioClient } from "@/core/storage/minio-client";
import { Readable } from "stream";

const BUCKET = process.env.MINIO_BUCKET_ANCPI || "ancpi-documente";

let bucketChecked = false;

/** Ensure the ANCPI bucket exists (idempotent, cached) */
export async function ensureAncpiBucket(): Promise<void> {
  if (bucketChecked) return;
  try {
    const exists = await minioClient.bucketExists(BUCKET);
    if (!exists) {
      await minioClient.makeBucket(BUCKET);
      console.log(`[epay-storage] Bucket '${BUCKET}' created.`);
    }
    bucketChecked = true;
  } catch (error) {
    console.error("[epay-storage] Bucket check/create failed:", error);
  }
}

/**
 * Get the next file index for a given cadastral number.
 * Scans existing objects to find the highest index.
 */
export async function getNextFileIndex(
  nrCadastral: string,
): Promise<number> {
  await ensureAncpiBucket();

  const pattern = new RegExp(
    `^(\\d+)_Extras CF_${nrCadastral.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")} -`,
  );

  let maxIndex = 0;
  const stream = minioClient.listObjects(BUCKET, "", true);

  return new Promise((resolve, reject) => {
    stream.on("data", (obj) => {
      if (!obj.name) return;
      const match = obj.name.match(pattern);
      if (match) {
        const idx = parseInt(match[1] ?? "0", 10);
        if (idx > maxIndex) maxIndex = idx;
      }
    });
    stream.on("end", () => resolve(maxIndex + 1));
    stream.on("error", reject);
  });
}

/**
 * Build the display filename for a CF extract.
 * Format: 01_Extras CF_291479 - 22-03-2026.pdf
 */
export function buildFileName(
  index: number,
  nrCadastral: string,
  date: Date,
): string {
  const idx = String(index).padStart(2, "0");
  const dd = String(date.getDate()).padStart(2, "0");
  const mm = String(date.getMonth() + 1).padStart(2, "0");
  const yyyy = date.getFullYear();
  return `${idx}_Extras CF_${nrCadastral} - ${dd}-${mm}-${yyyy}.pdf`;
}

/**
 * Store a CF extract PDF in MinIO.
 * Returns the MinIO path and file index.
 */
export async function storeCfExtract(
  pdfBuffer: Buffer,
  nrCadastral: string,
  metadata: Record<string, string>,
): Promise<{ path: string; fileName: string; index: number }> {
  await ensureAncpiBucket();

  const index = await getNextFileIndex(nrCadastral);
  const fileName = buildFileName(index, nrCadastral, new Date());
  // Store in subfolder per cadastral number
  const path = `parcele/${nrCadastral}/${fileName}`;

  // Strip diacritics from metadata values — MinIO headers only accept ASCII
  const safeMetadata: Record<string, string> = {
    "Content-Type": "application/pdf",
  };
  for (const [key, value] of Object.entries(metadata)) {
    safeMetadata[key] = value
      .normalize("NFD")
      .replace(/[\u0300-\u036f]/g, "");
  }

  await minioClient.putObject(BUCKET, path, pdfBuffer, pdfBuffer.length, safeMetadata);

  console.log(
    `[epay-storage] Stored: ${path} (${pdfBuffer.length} bytes)`,
  );

  return { path, fileName, index };
}

/**
 * Get a readable stream for a stored CF extract.
 */
export async function getCfExtractStream(
  minioPath: string,
): Promise<Readable> {
  return minioClient.getObject(BUCKET, minioPath);
}

/**
 * List all stored CF extracts for a cadastral number.
 */
export async function listExtractsForParcel(
  nrCadastral: string,
): Promise<Array<{ name: string; lastModified: Date; size: number }>> {
  await ensureAncpiBucket();

  const prefix = `parcele/${nrCadastral}/`;
  const results: Array<{ name: string; lastModified: Date; size: number }> =
    [];

  const stream = minioClient.listObjects(BUCKET, prefix, true);

  return new Promise((resolve, reject) => {
    stream.on("data", (obj) => {
      if (obj.name) {
        results.push({
          name: obj.name,
          lastModified: obj.lastModified ?? new Date(),
          size: obj.size ?? 0,
        });
      }
    });
    stream.on("end", () => resolve(results));
    stream.on("error", reject);
  });
}

/**
 * Generate a presigned download URL (7 day expiry).
 */
export async function getPresignedUrl(
  minioPath: string,
  expirySeconds = 7 * 24 * 3600,
): Promise<string> {
  return minioClient.presignedGetObject(BUCKET, minioPath, expirySeconds);
}
