import {Dimensions, PixelRatio, Platform} from 'react-native';
import dayjs, {Dayjs} from 'dayjs';
import {
  DeductionFrequencyType,
  DeductionNameType,
  FrequencyType,
  Grouped,
  InterestRateRangeType,
  SavingsAccountListType,
  SavingsCategoryType,
} from './types';
import {looseObject} from '../services/types';

export const {width, height} = Dimensions.get('window');

export const naira = '\u20A6';

const customWidth = 414;
const customHeight = 896;

export const ASPECT_RATIO = width / height;

export const scale = (size: number) => (width / customWidth) * size;

export const ms = (size: number, factor = 0.5) =>
  size + (scale(size) - size) * factor;

export const widthPercentageToDP = (widthPercent: number | string) => {
  const elemWidth =
    typeof widthPercent === 'number' ? widthPercent : parseFloat(widthPercent);

  return PixelRatio.roundToNearestPixel((width * elemWidth) / 100);
};

export const heightPercentageToDP = (heightPercent: number | string) => {
  const elemHeight =
    typeof heightPercent === 'number'
      ? heightPercent
      : parseFloat(heightPercent);

  return PixelRatio.roundToNearestPixel((height * elemHeight) / 100);
};

export const wp = (val: number) => {
  const percent = (val / customWidth) * 100;
  return widthPercentageToDP(percent);
};

/**
 * Converts fixed value to height % then to dp based on base design
 */
export const hp = (val: number) => {
  const percent = (val / customHeight) * 100;
  return heightPercentageToDP(percent);
};

export const isIphoneX = () => {
  const dimension = Dimensions.get('window');

  return (
    Platform.OS === 'ios' &&
    !Platform.isPad &&
    !Platform.isTV &&
    (dimension.height === 812 ||
      dimension.width === 812 ||
      dimension.height === 896 ||
      dimension.width === 896)
  );
};

export const fontSz = (val: number) => {
  return PixelRatio.roundToNearestPixel((height * val) / 100 / 8.5);
};

export const formatAmount = (value: any, toFixed = 2) => {
  return parseFloat(
    String(value)
      .replace(/(.*){1}/, '0$1')
      .replace(/[^\d]/g, '')
      .replace(/(\d\d?)$/, '.$1'),
  )
    .toFixed(toFixed)
    .replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};

export const formatAsCurrency = (value: number) =>
  `${naira}${parseFloat(String(value))
    .toFixed(2)
    .replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;

export const validateEmail = (email: any) => {
  const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
  return isValidEmail;
};

export function securePhoneNumber(phoneNumber: string): string {
  // Check if the input is a valid phone number
  if (!/^\d{11}$/.test(phoneNumber)) {
    return 'Invalid phone number';
  }

  // Extract the first 6 digits
  const visibleDigits = phoneNumber.substring(0, 6);

  // Replace the remaining digits with asterisks
  const secureValue = visibleDigits + '******';

  return secureValue;
}

export function secureEmail(email: string): string {
  const atIndex = email.indexOf('@');
  if (atIndex === -1) {
    return email; // Return the original email if '@' is not found
  }

  const [username, domain] = email.split('@');
  const secureUsername =
    username.slice(0, Math.min(username.length, 5)) +
    '*'.repeat(Math.max(0, username.length - 5));
  return `${secureUsername}@${domain}`;
}

export function isInteger(value: any, excludeDecimal?: boolean): boolean {
  // Check if the value is a number or a string that can be parsed as an integer
  if (
    typeof value === 'number' ||
    (typeof value === 'string' && !isNaN(parseInt(value)))
  ) {
    // Check if the parsed integer is equal to the original value
    if (excludeDecimal) {
      return (
        //@ts-ignore
        parseInt(value) === Number(value) && !value.toString().includes('.')
      );
    } else {
      //@ts-ignore
      return parseInt(value) === Number(value);
    }
  }
  return false;
}

export function extractNumber(input: string): number | string {
  try {
    const parts = input.split(',');
    const firstPart = parts[0].trim();
    const parsedNumber = parseInt(firstPart, 10);
    if (isNaN(parsedNumber)) {
      return ''; // Return undefined if the first part is not a valid number
    }
    return parsedNumber;
  } catch (error) {
    return '';
  }
}

export const capitalizeText = (text: string) => {
  return text && typeof text === 'string'
    ? text
        .toLowerCase()
        .split(' ')
        .map(word => word.charAt(0).toUpperCase() + word.slice(1))
        .join(' ')
    : '';
};

export function convertToISODateString(dateString: string): string {
  const date = dayjs(dateString);
  if (!date.isValid()) {
    return '';
  } else {
    return date.toISOString();
  }
}

export const correctFloatPoint = (number: number, point = 2) => {
  try {
    return Number(number.toFixed(point));
  } catch (error) {
    return number;
  }
};

export function calculateSavingsProgress(
  savingTarget: number,
  amountSaved: number,
): number | null {
  // Only calculate if both values are over 100
  if (savingTarget > 100 && amountSaved > 100) {
    const progress = (amountSaved / savingTarget) * 100;
    const cappedProgress = progress > 100 ? 100 : progress;
    return Math.ceil(cappedProgress); // Always round up to avoid showing 0%
  }

  return null; // Return null if conditions are not met
}

export const formatDate = (
  date: Date | string,
  format = 'MMM D, YYYY. h:mm a',
) => {
  return dayjs(date).format(format);
};

export const isTablet = (() => {
  // Basic heuristic:
  //  - Tablets generally have a minimum screen width > 600 dp (density-independent pixels)
  //  - iPads can be detected on iOS by model info but we skip that here for minimal deps

  const minTabletWidth = 600;

  // On iOS, some phones can have wide screens (like iPhone Plus models),
  // so you might want extra checks if desired.

  if (Platform.OS === 'web') {
    return false; // no tablets on web (or treat differently)
  }

  return Math.min(width, height) >= minTabletWidth;
})();

export const groupArray = <T,>(array: T[], field: keyof T): Grouped<T> => {
  return array?.reduce<Grouped<T>>((h, obj) => {
    const key = obj[field] as unknown as string;
    h[key] = (h[key] || []).concat(obj);
    return h;
  }, {});
};

export function getInterestRange(
  category: SavingsCategoryType,
): InterestRateRangeType {
  const {interestRate, interestRange} = category;
  
  // If interestRange is provided from backend, parse it
  if (interestRange) {
    const rangeMatch = interestRange.match(/(\d+(?:\.\d+)?)-(\d+(?:\.\d+)?)/);
    if (rangeMatch) {
      return {
        min: parseFloat(rangeMatch[1]),
        max: parseFloat(rangeMatch[2]),
      };
    }
  }
  
  // Fallback to old calculation if interestRange is not available
  return {
    min: interestRate - 2,
    max: interestRate + 2,
  };
}

export function getSaveAsYouCollectInterestRange(
  plans: {interestRate: number}[],
): string {
  if (!plans || plans.length === 0) {return 'N/A';}

  const rates = plans.map(plan => plan.interestRate);
  const minRate = Math.min(...rates);
  const maxRate = Math.max(...rates);

  return minRate === maxRate ? `${minRate}` : `${minRate} - ${maxRate}`;
}

export const getFrequencyEnum = (name: FrequencyType): number => {
  switch (name) {
    case 'Daily':
      return 1;
    case 'Weekly':
      return 2;
    case 'Monthly':
      return 3;
    case 'Save as you collect':
      return 4;
    default:
      return 0; // Default or unknown frequency
  }
};

export const getDeductionTypeEnum = (name: DeductionNameType): number => {
  switch (name) {
    case 'Percentage':
      return 2;
    case 'Flat rate':
      return 1;
    default:
      return 0; // Default or unknown type
  }
};
export const getDeductionFrequencyEnum = (
  name: DeductionFrequencyType,
): number => {
  switch (name) {
    case 'One-time':
      return 1;
    case 'Reoccurring':
      return 2;
    default:
      return 0; // Default or unknown frequency
  }
};

export const parseQueryString = (queryString: string) => {
  let query: looseObject = {};
  let pairs = (
    queryString[0] === '?' ? queryString.substr(1) : queryString
  ).split('&');
  for (let i = 0; i < pairs.length; i++) {
    let pair = pairs[i].split('=');
    //@ts-ignore
    const value = decodeURIComponent(pair[1] || '');
    query[decodeURIComponent(pair[0])] =
      value === 'true' ? true : value === 'false' ? false : value;
  }
  return query;
};

export const isValidDate = (date: any) => {
  return dayjs(date).isValid();
};

export const waitFor = (duration: number) => {
  return new Promise(resolve => setTimeout(resolve, duration || 0));
};

export const formDataRequests = [''];

// Returns ordinal suffix for numbers (1st, 2nd, 3rd, 4th, etc.)
export const getOrdinalSuffix = (num: number): string => {
  const j = num % 10;
  const k = num % 100;
  if (j === 1 && k !== 11) {return 'st';}
  if (j === 2 && k !== 12) {return 'nd';}
  if (j === 3 && k !== 13) {return 'rd';}
  return 'th';
};
