import moment from 'moment';
import {
  platforms, noDataCaseColorMapping, dateFormat, modelFamily,
  stepIds, trackerStatus, financialsType, PRIMARY_SCORE_TYPE, letterGradeScores,
  scalesNeedingModification, proSpreadScaleId, proSpreadPeriodMapping,
  extractedDataFromPage
} from '@root/constants';
import { constants } from '@spglobal/ca-mfe-package-utils';

export const formatDate = (date, dateFormat) =>
{
  if(date!== ''){
    return (moment(date).format(dateFormat));
  }
  return date;
};

export const isFutureDate = date => date > new Date();

export const selectedFormData = (formdata, target) => {
  const result = formdata.find(data => target in data);
  return result ? result[target] : [];
};

export const selectedFormField = (formdata, target) => {
  const result = formdata.find(item => item.name === target);
  return result ? result.value : '';
};

export const checkValidFormInput = updatedFormData => {
  const { modalFamily, companyType, industry, countryRegion } = updatedFormData;
  let isModalFamily = false;
  let isValidCompanyType = false;
  let isValidIndustry = false;
  let isValidCountryRegion = false;

  if (modalFamily.value !== '' && modalFamily.value !== undefined) {
    isModalFamily = true;
  }
  if (companyType.value !== '' && companyType.value !== undefined) {
    isValidCompanyType = true;
  }
  if (countryRegion.value !== '' && countryRegion.value !== undefined) {
    isValidCountryRegion = true;
  }
  if (industry.value !== '' && industry.value !== undefined) {
    isValidIndustry = true;
  }
  return {
    isModalFamily,
    isValidCompanyType,
    isValidIndustry,
    isValidCountryRegion
  };

};

export const stringformat = (s, replacedText) =>
s.toString().replace('{0}', replacedText);

export const generateFormInputList = formData => {
  const inputList = [];
  for (const key in formData) {
    if (formData.hasOwnProperty(key)) {
      inputList.push({
        name: key,
        value: formData[key]
      });
    }
  }
  return inputList;
};


export const sortFinancialStatement = list =>
  list.sort((a, b) => b.fiscalYear - a.fiscalYear || b.fiscalQuarter - a.fiscalQuarter);

export const sortSelectPeriod = list => list.sort((a, b) => b.fiscalYear - a.fiscalYear);

export const checkPrivateCompanyType = companyTypeId => ['2', '4'].includes(companyTypeId);
export const checkPrivateCorporateOnly = companyTypeId => companyTypeId === '2';

export const getCompanyID = () => {
  const href = window.location.search.toLowerCase();
  const params = new URLSearchParams(href);
  const company: any = {};
  if (href.indexOf('companyid') > -1) {
    company.companyID = params.get('companyid');
  } else if (href.indexOf('alternateid') > -1) {
    company.companyID = params.get('alternateid').toUpperCase();
    company.isUnlinkCompany = true;
  }
  return company;
};

const isLocalhost = window.location.hostname === 'localhost';

export const apiBase = isLocalhost ? 'https://www.testciq.com' : '';

export const getFormattedDate = formatDate(new Date(),dateFormat);

export const getCaHeader = (isProp = false) => constants.isCiqPlatform || isLocalhost ?
(isProp ? platforms.CIQPROP :platforms.CIQ) : platforms.CIQPro;

export const getDataSourceHeader = (datasource = platforms.CIQ) =>
  ({ 'ca-datasource': (constants.isCiqPlatform || isLocalhost) ? datasource : platforms.CIQPro });

export const formatDateValue = val => {
  const newDate = new Date(val);
  const toPadStr = val => val.toString().padStart(2, '0');
  const getMonth = toPadStr(newDate.getMonth()+1);
  const getDate = toPadStr(newDate.getDate());
  const getYear = newDate.getFullYear();
  return `${getYear}-${getMonth}-${getDate}`;
};

const formatWithIntl = (num: number) => new Intl.NumberFormat('en-US', {
    minimumFractionDigits: 0,
    maximumFractionDigits: 20
  }).format(num);

export const formatNumericValue = (val, decimals = 2, addComma = true) => {
  const [integerPart, decimalPart = ''] = String(val).split('.');
  const totalLength = integerPart.replace(/,/g, '').length + decimalPart.length;

  const addDecimal = num => {
    if (totalLength >= 16) {
      return formatWithIntl(num);
    }
    const maxAllowedDecimals = Math.max(0, 16 - integerPart.length);
    const paddedDecimal = decimalPart.length > decimals
    ? decimalPart.slice(0, decimals)
    : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0');
    return decimals === 0 ? `${integerPart}` : `${integerPart}.${paddedDecimal}`;
  };

  const separateWithComma = num => {
    if (totalLength >= 16) {
      return formatWithIntl(num);
    }
    const maxAllowedDecimals = Math.max(0, 16 - integerPart.length);
    const formattedNum = Math.floor(num).toLocaleString();
    const paddedDecimal = decimalPart.length > decimals
    ? decimalPart.slice(0, decimals)
    : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0');
    return decimals === 0 ? `${formattedNum}` : `${formattedNum}.${paddedDecimal}`;
  };

  if (val < 0) {
    const absValue = Math.abs(val);
    return `(${addComma ? separateWithComma(absValue) : addDecimal(absValue)})`;
  }

  return val !== null
    ? (addComma ? separateWithComma(Number(val)) : addDecimal(Number(val)))
    : val;
};

const padValue = (value, max, pad = 0.99) => value === max ? max : value + pad;

const getRanges = (clr, primaryScoreType, pdConfig: any = {}) => {
  if (primaryScoreType === PRIMARY_SCORE_TYPE.PD_PERCENT) {
    const { index, bandCount } = pdConfig;
    return {
      fromPd: clr.fromPd,
      toPd: clr.toPd,
      from: ((bandCount - 1 - index) * (100 / bandCount)),
      to: ((bandCount - 1 - index + 1) * (100 / bandCount))
    };
  }
  /*Note: For letterGrade, chart will be plotted based on oneToHundred score*/
  // else if (primaryScoreType === PRIMARY_SCORE_TYPE.LETTER_GRADE) {
  //   return {
  //     from: clr.fromLetterGrade,
  //     to: padValue(clr.toLetterGrade, 21)
  //   };
  // }
  return {
    from: clr.from === 0 ? clr.from - 0.99 : clr.from,
    to: padValue(Number(clr.to), 100)
  };
};

export const getGreyedoutBandColor = rgType => noDataCaseColorMapping.find(ob => ob.risktype === rgType)?.color;

export const getRgScoreMapColorBands = ({ plotBandColors, thickness = 20, primaryScoreType, noDataCase = false }) =>
  plotBandColors?.map((clr, index) => ({
    rgType: clr.rgType,
    color: noDataCase ? getGreyedoutBandColor(clr.rgType) : clr.color,
    ...getRanges(clr, primaryScoreType, { index, bandCount: plotBandColors?.length }),
    thickness
  }));

export const getTimestamp = data => {
  const date = new Date(data);
  return date.getTime();
};

export const getPercentageRounding = numbers => {

  const fixedTo10Nums = numbers.map(x => parseFloat(parseFloat(x).toFixed(10)));
  const total = Math.round(fixedTo10Nums.reduce((sum, e) => sum + e, 0));
  const remainder = total - fixedTo10Nums.reduce((sum, x) => sum + Math.floor(x), 0);

  const values = fixedTo10Nums
    .map((value, index) => ({
      index,
      value,
      remainder: Math.round((value % 1) * 100)
    }))
    .sort((a, b) => b.remainder - a.remainder)
    .map(({value, index}, idx)=>({
      index,
      value: (idx<remainder) ? Math.ceil(value): Math.floor(value)
    }))
    .sort((a, b) => a.index - b.index)
    .map(({value})=>value);

  return values;

};

export const calculateRevenueFromAssets = (assetVal, usdConvRate, decimals=2) => {
  if ((typeof assetVal === 'number') && usdConvRate) {
    const result = (2.5981 * (Math.pow(parseFloat((assetVal * usdConvRate).toString()), 0.7571))) / usdConvRate;
    return (truncateDecimal(result, decimals) ?? null);
  }
  return null;
};

export const truncateDecimal = (val, decimalPts = 1) => {
  if (typeof val === 'number') {
    const decimalFactor = Math.pow(10, decimalPts);
    return Math.floor(val * decimalFactor) / decimalFactor;
  }
  return null;
};

export const getDifference = (arr1 = [], arr2 = []) => [
  ...arr1.filter(x => !arr2.includes(x)),
  ...arr2.filter(x => !arr1.includes(x))
];

export const extractIndustry = (metaData, industryCode) => {
  const industriesData = metaData?.industries?.find(
    c => c.modelFamily === modelFamily.Risk_Gauge
  );
  const industries = industriesData?.industryTypes?.find(c =>
    c.options?.find(x => x.id.toString() === industryCode)
  );

  return {
    ...industries?.options?.find(x => x.id.toString() === industryCode),
    ...(industries?.type && { type: industries.type })
  };
};

export const extractCountry = (metaData, countryCode) => {
  const countriesData = metaData?.countries?.find(
    c => c.modelFamily === modelFamily.Risk_Gauge
  );
  const validCountry = countriesData?.options?.find(c => c.code === countryCode);

  return validCountry || {};
};

export const validateCountryIndustry = (metaData, industryCode, countryCode) => {
  const validIndustry = extractIndustry(metaData, industryCode);
  const validCountry = extractCountry(metaData, countryCode);
  return Boolean(Object.keys(validCountry).length) && Boolean(Object.keys(validIndustry).length);
};

export const getEnabledAdjStepsIds = steppers => {
  const adjSteps = steppers.find(steps => steps.stepId === stepIds.ADJUSTMENTS);
  return adjSteps?.nestedSteps.filter(({ status }) =>
    (status === trackerStatus.SELECTED || status === trackerStatus.ACTIVE || status === trackerStatus.COMPLETED))
    .map(({ stepId }) => stepId);
};

export const checkAdjEnabled = (steppers = [], adjId = '') => {
  const adjustments = steppers?.find(adj => adj.stepId === stepIds.ADJUSTMENTS);
  return adjustments?.nestedSteps?.find(ns => ns.stepId === adjId)?.showStep;
};

export const checkEpdCompany = (companyType, financialType) => companyType === '2'
  && financialType === financialsType.WithoutFinancials;

export const checkIsNotValidInput = (analyticsName, val) => {
  if(isNaN(val)){
    return true;
  }
  const numVal = Number(val);
  switch(analyticsName) {
    case 'GOVERNMENT_OWNERSHIP':
    case 'STANDALONE_PD_PARENT': {
      return Boolean(numVal < 0 || numVal > 100);
    }
    case 'TOTAL_EMPLOYEES': {
      return Boolean(numVal <= 0);
    }
    case 'ONLY_POSITIVE': {
      return Boolean(numVal > 0);
    }
    default:{
      return false;
    }
  }
};

export const rawPdFormatter = (rawPd, decimalPts = 4) => {
  if (typeof rawPd === 'number') {
    const tenPow = Math.pow(10, decimalPts);
    return Math.floor(rawPd * tenPow * 100) / tenPow;
  }
  return null;
};

export const displayScore = (value, scoreScaleType) => {
  if (scoreScaleType === PRIMARY_SCORE_TYPE.PD_PERCENT) {
    return `${value?.toFixed(4)}%`;
  } else if (scoreScaleType === PRIMARY_SCORE_TYPE.LETTER_GRADE) {
    return letterGradeScores[value];
  }
  return `${value}`;
};

export const getPrimaryAndSecondaryScore = (scoreScaleType, scoreObj) => {
  const scores: any = {};
  if (scoreScaleType === PRIMARY_SCORE_TYPE.LETTER_GRADE) {
    scores.primaryScore = scoreObj?.letterGradeNotch;
    /*Note: For letterGrade also chart will be plotted based on oneToHundred score*/
    scores.oneToHundred = scoreObj?.oneToHundred;
    scores.secondaryScore = rawPdFormatter(scoreObj?.rawPd);
    scores.secondaryScoreType = PRIMARY_SCORE_TYPE.PD_PERCENT;
  } else if (scoreScaleType === PRIMARY_SCORE_TYPE.PD_PERCENT) {
    scores.primaryScore = rawPdFormatter(scoreObj?.rawPd);
    scores.secondaryScore = scoreObj?.letterGradeNotch;
    scores.secondaryScoreType = PRIMARY_SCORE_TYPE.LETTER_GRADE;
    scores.oneToHundred = scoreObj?.oneToHundred;
  } else if (scoreScaleType === PRIMARY_SCORE_TYPE.ONE_TO_HUNDRED) {
    scores.primaryScore = scoreObj?.oneToHundred;
    scores.secondaryScore = scoreObj?.letterGradeNotch;
    scores.secondaryScoreType = PRIMARY_SCORE_TYPE.LETTER_GRADE;
    scores.oneToHundred = scoreObj?.oneToHundred;
  }
  return scores;
};

export const processProSpreadData = proSpreadData => {
  const { scaleId, instances = [], companyType = '', gicsCode, currencyName = '', compFinancial='',
    fromPage = '', isLinkedCompany = false, unlinkedSource = '' } = proSpreadData;
  proSpreadData.fromPage = fromPage;
  proSpreadData.companyType = companyType?.toUpperCase()?.indexOf('PUBLIC') > -1
  ? 'PUBLIC'
  : (fromPage === extractedDataFromPage)
  ? companyType: 'PRIVATE';
  proSpreadData.gicsCode = gicsCode ? `${gicsCode}` : gicsCode;
  proSpreadData.currencyName = currencyName.replace(/(^.*\[|\].*$)/g, '');
  proSpreadData.compFinancial = compFinancial;
  proSpreadData.isLinkedCompany = isLinkedCompany;
  proSpreadData.unlinkedSource = unlinkedSource;

  instances.forEach(currInstance => {
    const periodType = proSpreadPeriodMapping[currInstance.Period];
    currInstance.Period = periodType;
    currInstance.FQ = periodType === 'FY' ? 4 : currInstance.FQ;
    if (scalesNeedingModification.includes(scaleId)) {
      currInstance.Values.forEach(item => {
        switch (scaleId) {
          case proSpreadScaleId.thousands:
            item.Value /= 1000;
            break;
          case proSpreadScaleId.lac:
            item.Value /= 10;
            break;
          case proSpreadScaleId.billions:
            item.Value *= 1000;
            break;
          case proSpreadScaleId.absolute:
            item.Value /= 1000000;
            break;
          default:
            item.Value *= 1;
        }
      });
    }
  });
  return proSpreadData;
};

export const flatGroupsAndMetrics = (finData = []) => (
  finData?.reduce((acc, curr)=>{
    const newMetrics = curr.metrics.map(metric=>({
        ...metric,
        groupName: curr.groupName
      }));
    acc.push(...newMetrics);
    return acc;
  }, [])
);

export const parseSizeAdjustmentNumber = (val, decimals) => {
  const formattedValue = formatNumericValue(truncateDecimal(val, decimals), decimals);
  return formattedValue;
};

export const getValueFormat = (numValue, decimals = 2) => {
  const strNum = numValue?.toString().replaceAll(',', '');
  const [restrictedLength, displayDecimals] = [18, decimals];
  if (strNum?.length > restrictedLength) {
    const truncatedValue = addDecimalBasedOnValue(numValue, displayDecimals);
    return truncatedValue;
  }
  return numValue !== null ? formatNumericValue(numValue, displayDecimals) : numValue;
};

export const addDecimalBasedOnValue = (num, decimals = 2) => {
  const [integerPart, decimalPart = ''] = String(num).split('.');
  const totalLength = integerPart.length + decimalPart.length;
  if (num === '' || num === null) {
    return '';
  }
  if (totalLength >= 16) {
    return num.toString();
  }
  const maxAllowedDecimals = Math.max(0, 16 - integerPart.length);
  const paddedDecimal = decimalPart.length > decimals
    ? decimalPart.slice(0, decimals)
    : String(decimalPart).padEnd(Math.min(decimals, maxAllowedDecimals), '0');
  return decimals === 0 ? `${integerPart}` : `${integerPart}.${paddedDecimal}`;
};

export const trimValueToLength = (value, valDecLength = 18, valNumLength = 17) => {
  if (value) {
    const hasDecimal = value.includes('.');
    const maxLength = hasDecimal ? valDecLength : valNumLength;
    if (value.length >= maxLength) {
      const trimmedValue = value.slice(0, maxLength);
      return Number(trimmedValue);
    }
  }
  return undefined;
};

export const convertToNumber = value => {
  if (typeof value === 'number') {
    return value;
  } else if (typeof value === 'string' && !isNaN(value)) {
    return Number(value);
  }
  return null;
};

export const setDecimalLength = (decimalPart, numValue, decimalValue = 2) => {
  if (numValue !== null && numValue !== undefined && numValue !== '' && !isNaN(numValue)) {
    return decimalPart === '' ? 0 : decimalPart.length;
  }
  return decimalPart === '' ? decimalValue : decimalPart.length;
};
