import { assign } from 'ember-platform';
import Service from 'ember-service';
import computed from 'ember-computed';
import observer from 'ember-metal/observer';
import run from 'ember-runloop';
import injectService from 'ember-service/inject';
import { assert } from 'ember-metal/utils';
import { typeOf } from 'ember-utils';
import { LEFT_COLUMN_WIDTH_CLOSED, LEFT_COLUMN_WIDTH_OPEN,
         PERSISTENT_PLAYER_BOTTOM_MARGIN, PERSISTENT_PLAYER_LEFT_MARGIN} from 'web-client/services/layout';
import { getAbsoluteElementPosition, getFixedElementPosition } from 'web-client/utilities/element-position';

export const PLAYER_ANIMATION_DURATION = 350; // duration of the player grow/shrink animation in ms

const POS_STATE_FULLSIZE = 'state_full';
const POS_STATE_MINI = 'state_mini';

// The PRE_ANIMATION state is when the player has
// 'detached/reattached' to the main column but not begun moving
const POS_STATE_PRE_ANIMATION  = 'state_pre_anim';
const POS_STATE_ANIMATING = 'state_anim';

const END_TRANSITION_EVENT = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';

export default Service.extend({
  globals: injectService(),
  layout: injectService(),
  session: injectService(),
  storage: injectService(),
  persistentPlayerContent: injectService(),

  shouldShow: false,
  persistenceEnabled: true,
  positionState: POS_STATE_FULLSIZE,
  lastStaticState: POS_STATE_FULLSIZE,
  canBeFullSize: false,
  lockedInFullSize: false,
  fullSizePlayerLocation: {
    top: 0,
    left: 0
  },
  animationCoords: {
    originX: 0,
    originY: 0,
    translateX: 0,
    translateY: 0,
    scaleX: 0,
    scaleY: 0,
    position: 'absolute'
  },

  /**
   * format of queuedAnimation object
   * {
   *    destinationState: POS_STATE_MINI | POS_STATE_FULLSIZE,
   *    afterAnimate: the callback to be executed when the animation is complete
   * }
   */
  queuedAnimation: null,
  nextAnimationCallback: null,

  playerElement: null,
  playerComponent: null,

  isLeftColumnClosed: computed.readOnly('layout.isLeftColumnClosed'),

  init() {
    this._super(...arguments);
    this.syncPersistenceSetting();
  },

  isMini: computed.equal('positionState', POS_STATE_MINI),

  isAnimating: computed.equal('positionState', POS_STATE_ANIMATING),

  isPreAnimation: computed.equal('positionState', POS_STATE_PRE_ANIMATION),

  isFullSize: computed.equal('positionState', POS_STATE_FULLSIZE),

  isVisible: computed.and('persistentPlayerContent.hasContent', 'shouldShow'),

  isMiniPlayerVisible: computed.and('isVisible', 'isMini'),

  shouldPersist: computed('persistentPlayerContent.hasPlayableContent', 'persistenceEnabled', 'lockedInFullSize', function() {
    return (
      this.get('persistenceEnabled') &&
      !this.get('lockedInFullSize') &&
      this.get('persistentPlayerContent.hasPlayableContent')
    );
  }),

  persistentPlayerLocation: computed('layout.persistentPlayerDimensions', 'isLeftColumnClosed', function() {
    let dimensions = this.get('layout.persistentPlayerDimensions');
    let leftSidebarWidth = this.get('isLeftColumnClosed') ? LEFT_COLUMN_WIDTH_CLOSED : LEFT_COLUMN_WIDTH_OPEN;
    if (this.get('layout.isSocialColumnEnabled')) {
      leftSidebarWidth = 0;
    }

    let playerTopPosition = window.innerHeight - dimensions.height - PERSISTENT_PLAYER_BOTTOM_MARGIN;
    let playerLeftPosition = PERSISTENT_PLAYER_LEFT_MARGIN + leftSidebarWidth;

    return {
      top: playerTopPosition,
      left: playerLeftPosition
    };
  }),

  playerDimensions: computed('positionState', 'lastStaticState', 'layout.fullSizePlayerDimensions', 'layout.persistentPlayerDimensions', function() {
    let positionState = this.get('positionState');
    let lastStaticState = this.get('lastStaticState');
    let persistentPlayerDimensions = this.get('layout.persistentPlayerDimensions');
    let fullSizePlayerDimensions = this.get('layout.fullSizePlayerDimensions');

    if (positionState === POS_STATE_MINI) {
      return persistentPlayerDimensions;
    } else if (positionState === POS_STATE_FULLSIZE) {
      return fullSizePlayerDimensions;
    }

    return lastStaticState === POS_STATE_MINI ? persistentPlayerDimensions : fullSizePlayerDimensions;
  }),

  updateLastStaticState: observer('positionState', function() {
    let positionState = this.get('positionState');

    if (positionState === POS_STATE_MINI || positionState === POS_STATE_FULLSIZE) {
      this.set('lastStaticState', positionState);
    }
  }),

  onContentChange: observer('persistentPlayerContent.currentChannel', 'persistentPlayerContent.currentVOD', function() {
    if (this.get('isMiniPlayerVisible')) {
      this.trackMiniPlayerAction('content_change', '');
    }
  }),

  _queueAnimation(destinationState, afterAnimate) {
    if (destinationState === this.get('positionState')) {
      return;
    }

    assert('afterAnimate should be a function', typeOf(afterAnimate) === 'function');

    this.set('queuedAnimation', {
      destinationState: destinationState,
      afterAnimate: afterAnimate
    });
  },

  _setAnimationCoords(destinationState) {
    let playerElement = this.get('playerElement');

    if (playerElement === null) {
      return;
    }

    let originLocation = playerElement.position();

    if (this.get('isMini') && destinationState === POS_STATE_FULLSIZE) {
      originLocation = getAbsoluteElementPosition(playerElement);
    } else if (!this.get('isMini') && destinationState === POS_STATE_MINI) {
      originLocation = getFixedElementPosition(playerElement);
    }

    let destinationPosition = 'absolute';
    if (destinationState === POS_STATE_MINI) {
      destinationPosition = 'fixed';
    }

    let animationCoords = {
      originX: originLocation.left,
      originY: originLocation.top,
      position: destinationPosition
    };

    assign(animationCoords, this._getDestinationTransform(destinationState, originLocation));
    this.set('animationCoords', animationCoords);
  },

  _getDestinationTransform(destinationState, originLocation) {
    let destinationLocation, destinationSize;
    let originSize = this.get('playerDimensions');

    if (destinationState === POS_STATE_FULLSIZE) {
      destinationLocation = this.get('fullSizePlayerLocation');
      destinationSize = this.get('layout.fullSizePlayerDimensions');
    } else {
      destinationLocation = this.get('persistentPlayerLocation');
      destinationSize = this.get('layout.persistentPlayerDimensions');
    }

    let translateX = destinationLocation.left - originLocation.left;
    let translateY = destinationLocation.top - originLocation.top;
    let scaleX = destinationSize.width / originSize.width;
    let scaleY = destinationSize.height / originSize.height;

    return {
      translateX,
      translateY,
      scaleX,
      scaleY
    };
  },

  _flushAnimations() {
    let playerElement = this.get('playerElement');
    let queuedAnimation = this.get('queuedAnimation');

    if (playerElement === null || !this.get('isVisible') || queuedAnimation === null) {
      return;
    }

    this._setAnimationCoords(queuedAnimation.destinationState);
    this.set('positionState', POS_STATE_PRE_ANIMATION);

    run.next(this, () => {
      this.setProperties({
        nextAnimationCallback: this.get('queuedAnimation.afterAnimate'),
        queuedAnimation: null,
        positionState: POS_STATE_ANIMATING
      });
    });

    playerElement.one(END_TRANSITION_EVENT, () => {
      playerElement.off(END_TRANSITION_EVENT);

      run.next(this, () => {
        this.get('nextAnimationCallback')();

        if (this.get('queuedAnimation')) {
          this._flushAnimations();
        }
      });
    });
  },

  _isAnimationInProgress() {
    return this.get('isAnimating') || this.get('isPreAnimation');
  },

  setMini(value) {
    if (value) {
      this.set('positionState', POS_STATE_MINI);
    } else {
      this.set('positionState', POS_STATE_FULLSIZE);
    }
  },

  shrink(reason) {
    this._queueAnimation(POS_STATE_MINI, () => {
      this.set('positionState', POS_STATE_MINI);
      if (reason) {
        this.trackMiniPlayerAction('open', reason);
      }
      if (this.get('queuedAnimation.destinationState') === POS_STATE_MINI) {
        this.set('queuedAnimation', null);
      }
    });

    if (!this._isAnimationInProgress()) {
      this._flushAnimations();
    }
  },

  anchor(reason) {
    this._queueAnimation(POS_STATE_FULLSIZE, () => {
      this.set('positionState', POS_STATE_FULLSIZE);
      if (reason) {
        this.trackMiniPlayerAction('close', reason);
      }
      if (this.get('queuedAnimation.destinationState') === POS_STATE_FULLSIZE) {
        this.set('queuedAnimation', null);
      }
    });

    if (!this._isAnimationInProgress()) {
      this._flushAnimations();
    }
  },

  trackMiniPlayerAction(action, reason) {
    let playerComponent = this.get('playerComponent');

    if (!playerComponent) {
      return;
    }

    playerComponent.trackMiniPlayerAction(action, reason);
  },

  syncPersistenceSetting() {
    let persistenceEnabled = this.get('storage.persistenceEnabled');

    this.set('persistenceEnabled', persistenceEnabled !== 'false');
  }
});
