import { Types } from 'mongoose';
import { EmailAttachment } from '@/shared/email/email.interfaces';

export type ParseObjectType =
  | Record<string, string>
  | string
  | number
  | boolean
  | null
  | Date
  | undefined
  | Types.ObjectId
  | { [key: string]: ParseObjectType }
  | ParseObjectType[];

export const getObjectId = (value: string | Types.ObjectId): Types.ObjectId => {
  if (value instanceof Types.ObjectId) return value;

  if (Types.ObjectId.isValid(value)) return new Types.ObjectId(value);

  throw new Error('Invalid ObjectId');
};

export const capitalize = (value: string): string =>
  value.charAt(0).toUpperCase() + value.slice(1);

export function normalizeObjectIds(
  ids?: (Types.ObjectId | string)[],
): Types.ObjectId[] | undefined {
  if (!ids) return undefined;

  const uniqueIds = new Set<string>();
  const deduped: Types.ObjectId[] = [];

  for (const id of ids) {
    const strId = id.toString();
    if (!uniqueIds.has(strId)) {
      uniqueIds.add(strId);
      deduped.push(new Types.ObjectId(strId));
    }
  }

  return deduped;
}

export const parseObject = (passObj: ParseObjectType): ParseObjectType => {
  if (Array.isArray(passObj)) return passObj.map(parseObject);

  if (passObj instanceof Types.ObjectId) return { id: passObj.toString() };

  if (passObj instanceof Date) return passObj;

  if (passObj && typeof passObj === 'object') {
    const newObj: Record<string, ParseObjectType> = {};
    for (const key in passObj)
      if (Object.prototype.hasOwnProperty.call(passObj, key))
        newObj[key] = parseObject(passObj[key]);

    return newObj;
  }

  return passObj;
};

export const escapeRegex = (str: string) =>
  str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

export const getAvatarUrl = (name: string): string => {
  const seed = encodeURIComponent(name);
  return `https://api.dicebear.com/7.x/initials/svg?backgroundColor=FFB6C1,87CEFA,FFD700,98FB98,FFA07A,9370DB&textColor=222222&fontFamily=sans-serif&fontSize=45&fontWeight=400&seed=${seed}`;
};

export const getFullName = (user) => {
  if (!user) return 'N/A';
  return [user.firstName, user.lastName].filter(Boolean).join(' ');
};

export const getDialCodePhone = (phone) => {
  if (!phone?.dialCode || !phone?.number) return 'N/A';
  const phoneNumber = phone.dialCode + phone.number;
  return String(phoneNumber);
};

export const formattedAmount = (amount: number) =>
  new Intl.NumberFormat('en-IN', {
    style: 'currency',
    currency: 'INR',
  }).format(amount);

export const safeFallbackValues = (value?: string, fallback = 'N/A') =>
  value ?? fallback;

export const calculateBase64Size = (buffer: Buffer): number => {
  return Math.ceil(buffer.length * 4 / 3);
};

export const estimateEmailSize = (
  textContent?: string,
  htmlContent?: string,
  attachments?: EmailAttachment[],
): number => {
  let totalSize = 0;

  if (textContent) {
      totalSize += Buffer.byteLength(textContent, 'utf8');
  }

  if (htmlContent) {
      totalSize += Buffer.byteLength(htmlContent, 'utf8');
  }

  if (attachments?.length) {
      for (const attachment of attachments) {
          let buffer: Buffer;
          
          if (Buffer.isBuffer(attachment)) {
              // Handle Buffer[] case
              buffer = attachment;
          } else {
              // Handle EmailAttachment[] case
              if (!attachment.content) continue;
              buffer = Buffer.isBuffer(attachment.content) 
                  ? attachment.content 
                  : Buffer.from(attachment.content as string, 'utf8');
          }
          
          totalSize += calculateBase64Size(buffer);
          totalSize += 2048;
      }
  }
  totalSize += 5 * 1024;

  return totalSize;
};
export const parseSafeIds = (
  ids?: unknown,
): Types.ObjectId | { $in: Types.ObjectId[] } | undefined => {
  if (!ids) return undefined;

  let validIds: Types.ObjectId[] = [];

  if (ids instanceof Types.ObjectId) {
    return ids;
  }

  if (typeof ids === 'string') {
    validIds = ids
      .split(',')
      .map((id) => id.trim())
      .filter((id) => Types.ObjectId.isValid(id))
      .map((id) => new Types.ObjectId(id));
  }

  if (Array.isArray(ids)) {
    validIds = ids
      .map((id) => {
        if (id instanceof Types.ObjectId) return id;
        if (typeof id === 'string' && Types.ObjectId.isValid(id)) {
          return new Types.ObjectId(id);
        }
        return null;
      })
      .filter((id): id is Types.ObjectId => !!id);
  }

  if (validIds.length === 0) return undefined;
  return validIds.length === 1 ? validIds[0] : { $in: validIds };
};