import {
  DeleteObjectsCommand,
  GetObjectCommand,
  ListObjectsV2Command,
  PutObjectCommand,
  S3Client,
} from "@aws-sdk/client-s3";
import sharp from "sharp";

export const ORG_ICONS_BUCKET = "web-assets";

export const ICON_SIZES = [
  { size: 16, maskable: false },
  { size: 32, maskable: false },
  { size: 180, maskable: false },
  { size: 192, maskable: false },
  { size: 512, maskable: false },
  { size: 512, maskable: true },
] as const;

export function buildOrgIconKey(orgId: number, size: number, maskable = false): string {
  const suffix = maskable ? `-${size}-maskable` : `-${size}`;
  return `org-icons/${orgId}/icon${suffix}.png`;
}

export function buildOrgIconBasePath(orgId: number): string {
  return `org-icons/${orgId}/`;
}

export interface ResizedIcon {
  size: number;
  maskable: boolean;
  buffer: Buffer;
  key: string;
}

export async function resizeOrgIcon(inputBuffer: Buffer): Promise<ResizedIcon[]> {
  const metadata = await sharp(inputBuffer).metadata();
  if (!metadata.width || !metadata.height || metadata.width < 512 || metadata.height < 512) {
    throw new Error("Image must be minimum 512x512 pixels");
  }

  const results: ResizedIcon[] = [];

  for (const { size, maskable } of ICON_SIZES) {
    // For maskable icons, add 10% padding (safe zone) with white background
    if (maskable) {
      const innerSize = Math.round(size * 0.8);
      const resized = await sharp(inputBuffer)
        .resize(innerSize, innerSize, { fit: "cover" })
        .png()
        .toBuffer();

      const padded = await sharp({
        create: {
          width: size,
          height: size,
          channels: 4,
          background: { r: 255, g: 255, b: 255, alpha: 1 },
        },
      })
        .composite([{ input: resized, gravity: "center" }])
        .png()
        .toBuffer();

      results.push({
        size,
        maskable,
        buffer: padded,
        key: buildOrgIconKey(0, size, maskable),
      });
      continue;
    }

    const buffer = await sharp(inputBuffer).resize(size, size, { fit: "cover" }).png().toBuffer();
    results.push({
      size,
      maskable,
      buffer,
      key: buildOrgIconKey(0, size, maskable),
    });
  }

  return results;
}

export async function uploadOrgIcons(
  s3Client: S3Client,
  orgId: number,
  inputBuffer: Buffer
): Promise<string> {
  const resized = await resizeOrgIcon(inputBuffer);

  for (const icon of resized) {
    const key = buildOrgIconKey(orgId, icon.size, icon.maskable);
    await s3Client.send(
      new PutObjectCommand({
        Bucket: ORG_ICONS_BUCKET,
        Key: key,
        Body: icon.buffer,
        ContentType: "image/png",
      })
    );
  }

  return buildOrgIconBasePath(orgId);
}

export async function deleteOrgIcons(s3Client: S3Client, orgId: number): Promise<void> {
  const prefix = buildOrgIconBasePath(orgId);
  const listed = await s3Client.send(
    new ListObjectsV2Command({
      Bucket: ORG_ICONS_BUCKET,
      Prefix: prefix,
    })
  );

  if (!listed.Contents || listed.Contents.length === 0) return;

  await s3Client.send(
    new DeleteObjectsCommand({
      Bucket: ORG_ICONS_BUCKET,
      Delete: { Objects: listed.Contents.map(({ Key }) => ({ Key })) },
    })
  );
}

export async function getOrgIcon(
  s3Client: S3Client,
  orgId: number,
  size: number,
  maskable: boolean
): Promise<{ buffer: Buffer; contentType: string } | null> {
  const key = buildOrgIconKey(orgId, size, maskable);
  try {
    const response = await s3Client.send(
      new GetObjectCommand({
        Bucket: ORG_ICONS_BUCKET,
        Key: key,
      })
    );
    const body = await response.Body?.transformToByteArray();
    if (!body) return null;
    return { buffer: Buffer.from(body), contentType: "image/png" };
  } catch {
    return null;
  }
}
