import { FrameworkDelegate, Nav, PublicViewController } from '../../index';
import { STATE_ATTACHED, STATE_DESTROYED, STATE_INITIALIZED, STATE_NEW } from './nav-utils';

import {
  assert,
  normalizeUrl
} from '../../utils/helpers';

export class ViewController implements PublicViewController {

  id: string;
  data: any;
  element: HTMLElement;
  instance: any;
  state: number;
  nav: Nav;
  overlay: boolean;
  zIndex: number;
  dismissProxy: any;
  timestamp: number;
  fromExternalRouter: boolean;
  url: string;


  onDidDismiss: (data: any, role: string) => void;
  onWillDismiss: (data: any, role: string) => void;

  constructor(public component: any, data: any, fromExternalRouter: boolean, url: string) {
    initializeNewViewController(this, data, fromExternalRouter, url);
  }


  willLeave(unload: boolean): void {
    willLeaveImpl(unload, this);
  }

  didLeave(): void {
    didLeaveImpl(this);
  }

  willEnter(): void {
    callLifeCycleFunction(this.instance, 'ionViewWillEnter');
  }

  didEnter(): void {
    didEnterImpl(this);
  }

  willLoad(): void {
    willLoadImpl(this);
  }

  didLoad(): void {
    didLoadImpl(this);
  }

  willUnload(): void {
    willUnloadImpl(this);
  }

  destroy(delegate?: FrameworkDelegate): Promise<any> {
    return destroy(this, delegate);
  }
}

export function callLifecycle(instance: any, methodName: string) {
  instance && instance[methodName] && instance[methodName]();
}

export function destroy(viewController: ViewController, delegate?: FrameworkDelegate): Promise<any> {
  assert(viewController.state !== STATE_DESTROYED, 'view state must be attached');
  return delegate ? delegate.removeViewFromDom(viewController.nav.element, viewController.element) : Promise.resolve().then(() => {

    if (viewController.component) {
      // TODO - consider removing classes and styles as thats what we do in ionic-angular
    }

    viewController.id = viewController.data = viewController.element = viewController.instance = viewController.nav = viewController.dismissProxy = null;
    viewController.state = STATE_DESTROYED;
  });
}

export function callLifeCycleFunction(instance: any, functionName: string) {
  instance && instance[functionName] && instance[functionName]();
}

export function willLeaveImpl(unload: boolean, viewController: ViewController) {
  callLifeCycleFunction(viewController.instance, 'ionViewWillLeave');
  if (unload && viewController.onWillDismiss) {
    viewController.onWillDismiss(this.dismissProxy.data, this.dismissProxy.proxy);
    viewController.onWillDismiss = null;
  }
}

export function didLeaveImpl(viewController: ViewController) {
  callLifeCycleFunction(viewController.instance, 'ionViewDidLeave');
  // TODO, maybe need to do something framework specific here... figure this out later
  // for example, disconnecting from change detection
}

export function willEnterImpl(viewController: ViewController) {
  assert(viewController.state === STATE_ATTACHED, 'view state must be ATTACHED');
  // TODO, maybe need to do something framework specific here... figure this out later
  // for example, connecting to change detection
  callLifeCycleFunction(viewController.instance, 'ionViewWillEnter');
}

export function didEnterImpl(viewController: ViewController) {
  assert(viewController.state === STATE_ATTACHED, 'view state must be ATTACHED');
  // TODO - navbar didEnter here
  callLifeCycleFunction(viewController.instance, 'ionViewDidEnter');
}

export function willLoadImpl(viewController: ViewController) {
  assert(viewController.state === STATE_INITIALIZED, 'view state must be INITIALIZED');
  callLifeCycleFunction(viewController.instance, 'ionViewWillLoad');
}

export function willUnloadImpl(viewController: ViewController) {
  callLifeCycleFunction(viewController.instance, 'ionViewWillUnLoad');
  viewController.onDidDismiss && viewController.onDidDismiss(viewController.dismissProxy.data, viewController.dismissProxy.role);

  viewController.onDidDismiss = viewController.dismissProxy = null;
}

export function didLoadImpl(viewController: ViewController) {
  assert(viewController.state === STATE_ATTACHED, 'view state must be ATTACHED');
  callLifeCycleFunction(viewController.instance, 'ionViewDidLoad');
}

export function initializeNewViewController(viewController: ViewController, data: any, fromExternalRouter: boolean, url: string) {
  viewController.timestamp = Date.now();
  viewController.state = STATE_NEW;
  viewController.data = data || {};
  viewController.fromExternalRouter = fromExternalRouter;
  viewController.url = url && normalizeUrl(url);
}
