import { arSA, da, de, enGB, es, fr, is, it, nl, nb, pl, pt, sv, ja } from 'date-fns/locale';
import { format as formatDateFns } from 'date-fns';

export const languages = [
  'ar-SA',
  'da-DK',
  'de-DE',
  'en-GB',
  'es-ES',
  'fr-BE',
  'fr-FR',
  'is-IS',
  'it-IT',
  'nl-BE',
  'nl-NL',
  'no-NO',
  'pl-PL',
  'pt-PT',
  'sv-SE',
  'ja-JP'
];
export const defaultLanguage = 'nl-BE';

export const formatPrice = (price: number, currencyCode: string, locale: string = 'nl-BE') => {
  const priceFormat = Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currencyCode ? currencyCode : 'EUR',
    minimumFractionDigits: 2,
    useGrouping: true
  });
  return priceFormat.format(price);
};

import arJson from '../translations/ar-SA.json';
import daJson from '../translations/da-DK.json';
import deJson from '../translations/de-DE.json';
import enJson from '../translations/en-GB.json';
import esJson from '../translations/es-ES.json';
import frBeJson from '../translations/fr-BE.json';
import frFrJson from '../translations/fr-FR.json';
import isJson from '../translations/is-IS.json';
import itJson from '../translations/it-IT.json';
import nlBeJson from '../translations/nl-BE.json';
import nlNlJson from '../translations/nl-NL.json';
import noJson from '../translations/no-NO.json';
import plJson from '../translations/pl-PL.json';
import ptJson from '../translations/pt-PT.json';
import svJson from '../translations/sv-SE.json';
import jaJson from '../translations/ja-JP.json';
import { DateStruct } from '@qite/tide-client';
import { DepartureRange } from '../types';
import { SortByType } from '../../search-results/types';

export const getTranslations = (language: string) => {
  switch (language) {
    case 'ar-SA':
      return arJson;
    case 'da-DK':
      return daJson;
    case 'de-DE':
      return deJson;
    case 'en-GB':
      return enJson;
    case 'es-ES':
      return esJson;
    case 'fr-BE':
      return frBeJson;
    case 'fr-FR':
      return frFrJson;
    case 'is-IS':
      return isJson;
    case 'it-IT':
      return itJson;
    case 'nl-BE':
      return nlBeJson;
    case 'nl-NL':
      return nlNlJson;
    case 'no-NO':
      return noJson;
    case 'pl-PL':
      return plJson;
    case 'pt-PT':
      return ptJson;
    case 'sv-SE':
      return svJson;
    case 'ja-JP':
      return jaJson;
    default:
      throw new Error(`The language '${language}' is not yet supported.`);
  }
};

export const locales = {
  'ar-SA': arSA,
  'da-DK': da,
  'de-DE': de,
  'en-GB': enGB,
  'es-ES': es,
  'fr-BE': fr,
  'fr-FR': fr,
  'is-IS': is,
  'it-IT': it,
  'nl-BE': nl,
  'nl-NL': nl,
  'no-NO': nb,
  'pl-PL': pl,
  'pt-PT': pt,
  'sv-SE': sv,
  'ja-JP': ja
};

export function getLocale(code: string) {
  switch (code) {
    case 'ar-SA':
      return locales[code];
    case 'da-DK':
      return locales[code];
    case 'de-DE':
      return locales[code];
    case 'en-GB':
      return locales[code];
    case 'es-ES':
      return locales[code];
    case 'fr-BE':
      return locales[code];
    case 'fr-FR':
      return locales[code];
    case 'is-IS':
      return locales[code];
    case 'it-IT':
      return locales[code];
    case 'nl-BE':
      return locales[code];
    case 'nl-NL':
      return locales[code];
    case 'no-NO':
      return locales[code];
    case 'pl-PL':
      return locales[code];
    case 'pt-PT':
      return locales[code];
    case 'sv-SE':
      return locales[code];
    case 'ja-JP':
      return locales[code];
    default:
      return locales['nl-BE'];
  }
}

export const getPriceDifferenceText = (price: number, currencyCode: string) => {
  return price > 0 ? `+ ${formatPrice(Math.abs(price), currencyCode)}` : `- ${formatPrice(Math.abs(price), currencyCode)}`;
};

export function format(text: string, args: any[]) {
  return text.replace(/{([0-9]+)}/g, function (match, index) {
    return typeof args[index] == 'undefined' ? match : args[index];
  });
}

export const formatTime = (date: Date) =>
  new Intl.DateTimeFormat('nl-BE', {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false
  }).format(new Date(date));

export const formatDate = (date: Date) =>
  new Intl.DateTimeFormat('nl-BE', {
    weekday: 'short',
    day: '2-digit',
    month: 'short',
    year: '2-digit'
  }).format(new Date(date));

export const dateToDateStruct = (date: Date | undefined): DateStruct => {
  if (date === undefined) {
    return { year: 0, month: 0, day: 0 };
  }
  return {
    year: date.getFullYear(),
    month: date.getMonth() + 1, // Months are 0-based in JS
    day: date.getDate()
  };
};

export const timeFromDateTime = (dateTime: Date | undefined): string => {
  if (!dateTime) {
    return '';
  }

  const value = dateTime as Date | string;

  if (typeof value === 'string') {
    return value.match(/T(\d{2}:\d{2})/)?.[1] ?? '';
  }

  return `${value.getHours().toString().padStart(2, '0')}:${value.getMinutes().toString().padStart(2, '0')}`;
};

export const longFormatDate = (dateTime: Date | undefined, language: string): string => {
  if (!dateTime) {
    return '';
  }
  const locale = getLocale(language);
  const formattedDate = formatDateFns(new Date(dateTime), 'eee dd MMM yy', { locale });
  return formattedDate;
};

export const durationTicksInHoursString = (durationInTicks: number): string => {
  const totalMinutes = Math.floor(durationInTicks / 10_000 / 1000 / 60);
  return minutesToHoursString(totalMinutes);
};

export const durationInTicksInMinutes = (durationInTicks: number): number => {
  const totalMinutes = Math.floor(durationInTicks / 10_000 / 1000 / 60);
  return totalMinutes;
};

export const minutesToHoursString = (totalMinutes: number): string => {
  const hours = Math.floor(totalMinutes / 60);
  const minutes = totalMinutes % 60;

  const paddedMinutes = minutes.toString().padStart(2, '0');

  return `${hours.toString()} h ${paddedMinutes}`;
};

export const rangeFromDateTimeInMinutes = (dateTime: Date | undefined): DepartureRange => {
  if (!dateTime) {
    return DepartureRange.Morning;
  }
  const date = new Date(dateTime);
  const hours = date.getHours();
  const minutes = hours * 60 + date.getMinutes();
  switch (true) {
    case minutes >= 300 && minutes < 720:
      return DepartureRange.Morning;
    case minutes >= 720 && minutes < 1080:
      return DepartureRange.Afternoon;
    case minutes >= 1080 && minutes < 1440:
      return DepartureRange.Evening;
    default:
      return DepartureRange.Night;
  }
};

export const calculateNights = (fromDate: Date, toDate: Date): number => {
  const from = new Date(fromDate);
  const to = new Date(toDate);

  // Normalize to midnight to avoid time issues
  from.setHours(0, 0, 0, 0);
  to.setHours(0, 0, 0, 0);

  const diffTime = to.getTime() - from.getTime();
  return Math.round(diffTime / (1000 * 60 * 60 * 24));
};

export const calculateDays = (fromDate: Date, toDate: Date): number => {
  return calculateNights(fromDate, toDate) + 1;
};

export const getSortingName = (translations: any, sortByType: SortByType): string => {
  switch (sortByType.label) {
    case 'price':
      return sortByType.direction === 'asc' ? translations.SRP.PRICE_ASC : translations.SRP.PRICE_DESC;
    case 'departureTime':
      return sortByType.direction === 'asc' ? translations.SRP.DEPARTURE_TIME_ASC : translations.SRP.DEPARTURE_TIME_DESC;
    case 'durationInTicks':
      return sortByType.direction === 'asc' ? translations.SRP.DURATION_ASC : translations.SRP.DURATION_DESC;
    default:
      return sortByType.label;
  }
};

export const findSortByType = (sortByTypes: SortByType[], sortKey: string, direction: string) => {
  return sortByTypes.find((s) => s.label === sortKey && s.direction === direction) || sortByTypes[0];
};

export const getDatesBetween = (fromDate: string, toDate: string): Date[] => {
  const dates: Date[] = [];

  const current = new Date(fromDate);
  const end = new Date(toDate);

  while (current < end) {
    dates.push(new Date(current));
    current.setUTCDate(current.getUTCDate() + 1);
  }

  return dates;
};

export const getDateOnlyTime = (date?: string | Date | null) => {
  if (!date) return 0;

  const parsedDate = new Date(date);

  return new Date(parsedDate.getFullYear(), parsedDate.getMonth(), parsedDate.getDate()).getTime();
};
