import {
  animate,
  AnimationTransitionMetadata,
  group,
  query,
  style,
  transition,
  trigger,
} from '@angular/animations';

/**
 *
 * @param fromStyle starting css style object of the leaving page
 * @param toStyle starting css style object of the entering page
 * @param direction  in which direction the page will slide to
 * @returns {(AnimationQueryMetadata | AnimationGroupMetadata)[]}
 */
const slideFromXToYWithDirection = (
  fromStyle: { [key: string]: number | string },
  toStyle: { [key: string]: number | string },
  direction: 'left' | 'right'
) => {
  /** animation templates for left and right sliding */
  const directionConfig = {
    right: [
      query(':leave', style({ transform: 'translateX(0%)' }), {
        optional: true,
      }),
      query(':enter', style({ transform: 'translateX(100%)' }), {
        optional: true,
      }),
      group([
        query(':leave', [animate('200ms ease-in-out', style({ transform: 'translateX(-100%)' }))], {
          optional: true,
        }),
        query(':enter', [animate('200ms ease-in-out', style({ transform: 'translateX(0%)' }))], {
          optional: true,
        }),
      ]),
    ],
    left: [
      query(':leave', style({ transform: 'translateX(0%)' }), {
        optional: true,
      }),
      query(':enter', style({ transform: 'translateX(-100%)' }), {
        optional: true,
      }),
      group([
        query(':leave', [animate('200ms ease-in-out', style({ transform: 'translateX(100%)' }))], {
          optional: true,
        }),
        query(':enter', [animate('200ms ease-in-out', style({ transform: 'translateX(0%)' }))], {
          optional: true,
        }),
      ]),
    ],
  };

  return [
    query(
      ':leave',
      style({
        ...fromStyle,
      }),
      {
        optional: true,
      }
    ),
    query(
      ':enter',
      style({
        ...toStyle,
      }),
      {
        optional: true,
      }
    ),
    ...directionConfig[direction],
    // triggering children components with change
    query(
      'router-outlet ~ *',
      [
        style({
          opacity: 0.99999,
        }),
        animate(
          '200ms ease',
          style({
            opacity: 1,
          })
        ),
      ],
      { optional: true }
    ),
  ];
};

// default fixed style for animations
const baseStyle = {
  position: 'fixed',
  left: 0,
  right: 0,
  top: 64, // header
  bottom: 0,
};
// default fixed style for animations for pages with news bar open
const baseStyleWithNewsBar = {
  position: 'fixed',
  left: 0,
  right: 0,
  top: 64 + 52, // header + news bar
  bottom: 0,
};
const settingsStyle = {
  position: 'fixed',
  height: '91%', // fixes some bugs occuring only on setting pages
  left: 0,
  right: 0,
  top: 64, // header
  bottom: 0,
};

type SingleAnimation = {
  name: string;
  position: number;
  style: { [key: string]: string | number };
};
type AnimationArray = SingleAnimation[];

/**
 * Animation config for components on the AppComponent router-outlet.
 */
const AppComponentAnimations: AnimationArray = [
  { name: 'homePage', position: 0, style: baseStyleWithNewsBar },
  { name: 'resourcePage', position: 1, style: baseStyleWithNewsBar },
  { name: 'mainMenu', position: 1, style: settingsStyle },
  { name: 'mainMenu-settings', position: 2, style: settingsStyle },
  { name: 'mainMenu-licenses', position: 2, style: settingsStyle },
  { name: 'mainMenu-licenseBuy', position: 2, style: settingsStyle },
  { name: 'mainMenu-nanoManager', position: 2, style: settingsStyle },
  { name: 'mainMenu-account', position: 2, style: settingsStyle },
  { name: 'mainMenu-contactList', position: 2, style: settingsStyle },
  { name: 'mainMenu-offers', position: 2, style: settingsStyle },
  { name: 'mainMenu-nanoMetrics', position: 2, style: settingsStyle },
  { name: 'mainMenu-saleCodeManager', position: 2, style: settingsStyle },
  {
    name: 'mainMenu-settings-advancedSettings',
    position: 3,
    style: settingsStyle,
  },
  {
    name: 'mainMenu-settings-about',
    position: 3,
    style: settingsStyle,
  },
  {
    name: 'mainMenu-account-sessionHandler',
    position: 3,
    style: settingsStyle,
  },

  { name: 'loginPage', position: 0, style: baseStyle },
  { name: 'rightFromLogin', position: 1, style: baseStyle },
  { name: 'rightFromMainMenu', position: 2, style: baseStyle },
];

/**
 * Animation config for components on the ResourcePageMobile router-outlet
 */
const ResourcePageMobileAnimations: AnimationArray = [
  { name: 'resourcePage-chat', position: 1, style: baseStyleWithNewsBar },
  { name: 'resourcePage-chat-drive', position: 2, style: baseStyleWithNewsBar },
  { name: 'resourcePage-chat-details', position: 3, style: baseStyleWithNewsBar },
];

const RouterOutletAnimationArrays = [AppComponentAnimations, ResourcePageMobileAnimations];

/**
 * Generates the animation object from the config of the entering and leaving pages.
 * Can return null, if the two pages should not transition with animations
 *
 * @param page1 animation config of the leaving page
 * @param page2 animation config of the entering page
 * @returns {AnimationTransitionMetadata|null} transition object for animation or null
 */
const generateSingleAnimation = (page1: SingleAnimation, page2: SingleAnimation) => {
  const { name: name1, position: pos1, style: style1 } = page1;
  const { name: name2, position: pos2, style: style2 } = page2;

  if (pos1 < pos2) {
    // right slide
    return transition(`${name1} => ${name2}`, slideFromXToYWithDirection(style1, style2, 'right'));
  }
  if (pos1 > pos2) {
    // left slide
    return transition(`${name1} => ${name2}`, slideFromXToYWithDirection(style1, style2, 'left'));
  }
  // no animations
  return null;
};

/**
 * Manually given custom transition between pages
 */
const CustomAnimations = [transition('resourcePage => resourcePage', [])];

/**
 * Generates animations with {@link generateSingleAnimation} for route transitions with the config of {@link RouterOutletAnimationArrays} and {@link customAnimations}.
 *
 * @returns {AnimationTransitionMetadata[]} page animations
 */
const generateAnimations = () => {
  const generatedAnimations: AnimationTransitionMetadata[] = [...CustomAnimations];
  for (const animArray of RouterOutletAnimationArrays) {
    for (let i = 0; i < animArray.length; i++) {
      for (let j = 0; j < animArray.length; j++) {
        const page1 = animArray[i];
        const page2 = animArray[j];

        const anim: AnimationTransitionMetadata | null = generateSingleAnimation(page1, page2);
        if (anim) {
          generatedAnimations.push(anim);
        }
      }
    }
  }

  return generatedAnimations;
};

const generatedAnimations = generateAnimations();
//console.log('animations', [trigger('routeTransition', generatedAnimations)]);

export const resourcePageMobileAnimations = [trigger('routeTransition', generatedAnimations)];
export const appComponentAnimations = [trigger('routeTransition', generatedAnimations)];
