'use strict';

// TODO : demo for router is in its own file, so remove this at some point
// TODO : DOCUMENTATION : all settings which should not be inherited from the
// parent should have default value. This prevents unintentional overriding
// from the ancestor hierarchy. Settings' default value should be part of
// the component documentation

define(function (require) {
  var Rx = require('rx');
  var U = require('util');
  var m = U.m;
  var Cycle = require('cycle');
  var Router = require('components/Router');
  //    const toHTML = require('vdomtohtml')
  var Sdom = require('cycle-snabbdom');
  var Sdom2html = require('snabbdom-to-html').toHTML;
  var makeDOMDriver = Sdom.makeDOMDriver;
  var makeHTMLDriver = Sdom.makeHTMLDriver;
  var h = Sdom.h,
      h2 = Sdom.h2,
      h3 = Sdom.h3,
      div = Sdom.div,
      p = Sdom.p,
      ul = Sdom.ul,
      li = Sdom.li,
      span = Sdom.span,
      a = Sdom.a,
      i = Sdom.i;

  var Mclass = require('snabbdom_class');
  var Mprops = require('snabbdom_props');
  var Mstyle = require('snabbdom_style');
  var Mattributes = require('snabbdom_attributes');

  var modules = [Mclass, Mprops, Mstyle, Mattributes];
  var $ = Rx.Observable;

  var createBrowserHistory = require('history').createBrowserHistory;
  var history = createBrowserHistory();
  var makeHistoryDriver = require('history_driver.js').makeHistoryDriver;

  var historyDriver = makeHistoryDriver(history, { capture: true });

  function makeFakeAuthDriver() {
    return function authDriver(authIntent$) {
      authIntent$.tap(console.log.bind(console, 'authDriver : authIntent$ :'));
    };
  }

  function makeFakeQueueDriver() {
    return function queueDriver(queueIntent$) {
      queueIntent$.tap(console.log.bind(console, 'queueDriver : queueIntent$ :'));
    };
  }

  function filterNull(driver) {
    return function filteredDOMDriver(sink$) {
      return driver(sink$.filter(function (x) {
        return x;
      }));
    };
  }

  var drivers = {
    DOM: filterNull(makeDOMDriver('#app', { transposition: false, modules: modules })),
    router: historyDriver
  };

  /**
   * FIXTURES
   */
  var App = { Group: {}, User: {} };

  App.Group.FIXTURES = [{
    id: 1,
    name: "Group one",
    details: "details for Group one",
    users: [1, 2]

  }, {
    id: 2,
    name: "Group two",
    details: "details for Group two",
    users: [2]
  }];

  App.User.FIXTURES = [{
    id: 1,
    name: "Tom",
    details: "I am the Cat !",
    groups: [1]

  }, {
    id: 2,
    name: "Jerry",
    details: "I am the Mouse !",
    groups: [2]
  }];

  /**
   * Rendering functions
   */
  function renderGroups(groups) {
    return div([h3('Groups'), p('Click on a group to display corresponding users'), div({ style: '' }, [ul(groups.map(function (group) {
      return li([a({
        "attrs": { "href": '/group/' + group.id }
      }, [group.name])]);
    }))])]);
  }

  function renderUsers(groupID, userIDs) {
    var users = userIDs.map(function (x) {
      return App.User.FIXTURES[x - 1];
    });

    return div([h3('Users'), p('Click on an user to display the details'), div([ul(users.map(function (user) {
      return li([a({
        "attrs": { "href": '/group/' + groupID + '/user/' + user.id }
      }, [user.name])]);
    }))])]);
  }

  function renderDetails(model) {
    return div([h3('Details for ' + model.name), div([i('' + model.details)])]);
  }

  var groups = App.Group.FIXTURES;
  var users = App.User.FIXTURES;

  function main(sources) {

    console.log('render group', Sdom2html(renderGroups(groups)));

    var setUpSources = {
      makeLocalSources: function makeShowGroupCoreExtraSources(sources) {
        var route$ = sources.router.pluck('pathname').map(function (route) {
          return route && route[0] === '/' ? route.substring(1) : route;
        });
        route$.subscribe(console.log.bind(console, 'route'));
        return {
          route$: route$
        };
      },
      makeLocalSettings: function makeLocalSettings(settings) {
        return { sinkNames: ['DOM', 'router'] };
      }
    };

    var showGroupCore = {
      makeOwnSinks: function showGroupCore(sources, settings) {
        return {
          DOM: $.of(renderGroups(groups))
        };
      }
    };

    var showUserDetails = function showUserDetails(sources, settings) {
      var userID = settings.routeParams.userId;

      return {
        DOM: $.of(renderDetails(users[userID - 1]))
      };
    };

    var showUsersCore = {
      makeOwnSinks: function showUsersCore(sources, settings) {
        var groupID = settings.routeParams.groupId;

        return {
          DOM: $.of(renderUsers(groupID, groups[groupID - 1].users))
        };
      }
    };

    var showGroupDetails = m(showUsersCore, {}, [m(Router, { route: 'user/:userId' }, [showUserDetails])]);

    var page = m(setUpSources, {}, [m(showGroupCore, {}, [m(Router, { route: 'group/:groupId' }, [showGroupDetails])])]);

    var pageSinks = page(sources, {});

    return {
      DOM: pageSinks.DOM,
      router: $.never()
    };
  }

  // NOTE : Implements a circular flow with : main(drivers(replayS)).subscribe(replayS)
  Cycle.run(main, drivers);
});