// import { s3A, awsBucketName, awsRegion, awsSecretAccessKey } from "@/src/lib/env-exporter"
import { DeleteObjectCommand, DeleteObjectsCommand, PutObjectCommand, S3Client, GetObjectCommand } from "@aws-sdk/client-s3"
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
import signedUrlCache from "@/src/lib/signed-url-cache"
import { s3AccessKeyId, s3Region, s3Url, s3SecretAccessKey, s3BucketName, assetsDomain } from "@/src/lib/env-exporter"
import { db } from "@/src/db/db_index"; // Adjust path if needed
import { uploadUrlStatus } from "@/src/db/schema"
import { and, eq } from 'drizzle-orm';

const s3Client = new S3Client({
  region: s3Region,
  endpoint: s3Url,
  forcePathStyle: true,
  credentials: {
    accessKeyId: s3AccessKeyId,
    secretAccessKey: s3SecretAccessKey,
  },
})
export default s3Client;

export const imageUploadS3 = async(body: Buffer<ArrayBufferLike>, type: string, key:string) => {
  // const key = `${category}/${Date.now()}`
  const command = new PutObjectCommand({
    Bucket: s3BucketName,
    Key: key,
    Body: body,
    ContentType: type,
  })
  const resp = await s3Client.send(command)
  
  const imageUrl = `${key}`
  return imageUrl;
}


// export async function deleteImageUtil(...keys:string[]):Promise<boolean>;

export async function deleteImageUtil({bucket = s3BucketName, keys}:{bucket?:string, keys: string[]}) {
  
  if (keys.length === 0) {
    return true;
  }
  try {
    const deleteParams = {
      Bucket: bucket,
      Delete: {
        Objects: keys.map((key) => ({ Key: key })),
        Quiet: false,
      }
    }
    
    const deleteCommand = new DeleteObjectsCommand(deleteParams)
    await s3Client.send(deleteCommand)
    return true
  }
  catch (error) {
    console.error("Error deleting image:", error)
    throw new Error("Failed to delete image")
    return false;
  }
}

export function scaffoldAssetUrl(input: string | null): string
export function scaffoldAssetUrl(input: (string | null)[]): string[]
export function scaffoldAssetUrl(input: string | null | (string | null)[]): string | string[] {
  if (Array.isArray(input)) {
    return input.map(key => scaffoldAssetUrl(key) as string);
  }
  if (!input) {
    return '';
  }
  const normalizedKey = input.replace(/^\/+/, '');
  const domain = assetsDomain.endsWith('/')
    ? assetsDomain.slice(0, -1)
    : assetsDomain;
  return `${domain}/${normalizedKey}`;
}


/**
 * Generate a signed URL from an S3 URL
 * @param s3Url The full S3 URL (e.g., https://bucket-name.s3.region.amazonaws.com/path/to/object)
 * @param expiresIn Expiration time in seconds (default: 259200 seconds = 3 days)
 * @returns A pre-signed URL that provides temporary access to the object
 */
export async function generateSignedUrlFromS3Url(s3UrlRaw: string|null, expiresIn: number = 259200): Promise<string> {
  if (!s3UrlRaw) {
    return '';
  }

  const s3Url = s3UrlRaw
  
  try {
    // Check if we have a cached signed URL
    const cachedUrl = signedUrlCache.get(s3Url);
    if (cachedUrl) {
      // Found in cache, return it
      return cachedUrl;
    }
    
    // Create the command to get the object
    const command = new GetObjectCommand({
      Bucket: s3BucketName,
      Key: s3Url,
    });
    
    // Generate the signed URL
    const signedUrl = await getSignedUrl(s3Client, command, { expiresIn });
    
    // Cache the signed URL with TTL matching the expiration time (convert seconds to milliseconds)
    signedUrlCache.set(s3Url, signedUrl, (expiresIn * 1000) - 60000); // Subtract 1 minute to ensure it doesn't expire before use
    
    return signedUrl;
  } catch (error) {
    console.error("Error generating signed URL:", error);
    throw new Error("Failed to generate signed URL");
  }
}

/**
 * Get the original S3 URL from a signed URL
 * @param signedUrl The signed URL 
 * @returns The original S3 URL if found in cache, otherwise null
 */
export function getOriginalUrlFromSignedUrl(signedUrl: string|null): string|null {
  if (!signedUrl) {
    return null;
  }
  
  // Try to find the original URL in our cache
  const originalUrl = signedUrlCache.getOriginalUrl(signedUrl);
  
  return originalUrl || null;
}

/**
 * Generate signed URLs for multiple S3 URLs
 * @param s3Urls Array of S3 URLs or null values
 * @param expiresIn Expiration time in seconds (default: 259200 seconds = 3 days)
 * @returns Array of signed URLs (empty strings for null/invalid inputs)
 */
export async function generateSignedUrlsFromS3Urls(s3Urls: (string|null)[], expiresIn: number = 259200): Promise<string[]> {
  if (!s3Urls || !s3Urls.length) {
    return [];
  }

  try {
    // Process URLs in parallel for better performance
    const signedUrls = await Promise.all(
      s3Urls.map(url => generateSignedUrlFromS3Url(url, expiresIn).catch(() => ''))
    );
    
    return signedUrls;
  } catch (error) {
    console.error("Error generating multiple signed URLs:", error);
    // Return an array of empty strings with the same length as input
    return s3Urls.map(() => '');
  }
}

export async function generateUploadUrl(key: string, mimeType: string, expiresIn: number = 180): Promise<string> {
  try {
    // Insert record into upload_url_status
    await db.insert(uploadUrlStatus).values({
      key: key,
      status: 'pending',
    });

    // Generate signed upload URL
    const command = new PutObjectCommand({
      Bucket: s3BucketName,
      Key: key,
      ContentType: mimeType,
    });

    const signedUrl = await getSignedUrl(s3Client, command, { expiresIn });
    return signedUrl;
  } catch (error) {
    console.error('Error generating upload URL:', error);
    throw new Error('Failed to generate upload URL');
  }
}


// export function extractKeyFromPresignedUrl(url:string) {
//   const u = new URL(url);
//   const rawKey = u.pathname.replace(/^\/+/, ""); // remove leading slash
//   return decodeURIComponent(rawKey);
// }

// New function (excludes bucket name)
export function extractKeyFromPresignedUrl(url: string): string {
  const u = new URL(url);
  const rawKey = u.pathname.replace(/^\/+/, ""); // remove leading slash
  const decodedKey = decodeURIComponent(rawKey);
  // Remove bucket prefix
  const parts = decodedKey.split('/');
  parts.shift(); // Remove bucket name
  return parts.join('/');
}

export async function claimUploadUrl(url: string): Promise<void> {
  try {
    const semiKey = extractKeyFromPresignedUrl(url);
    const key = s3BucketName+'/'+ semiKey

    // Update status to 'claimed' if currently 'pending'
    const result = await db
      .update(uploadUrlStatus)
      .set({ status: 'claimed' })
      .where(and(eq(uploadUrlStatus.key, semiKey), eq(uploadUrlStatus.status, 'pending')))
      .returning();
    
    if (result.length === 0) {
      throw new Error('Upload URL not found or already claimed');
    }
  } catch (error) {
    console.error('Error claiming upload URL:', error);
    throw new Error('Failed to claim upload URL');
  }
}
