/* globals URI */

import serialize from 'web-client/mirage/utils/serialize';
import Mirage from 'ember-cli-mirage';
import pageParams from 'web-client/mirage/utils/page-params';
import { assign } from 'ember-platform';
import { parseQueryParams } from 'web-client/utilities/url-params';
import omit from 'web-client/utilities/omit';
import { ARCHIVE_TYPE_PARAM, HIGHLIGHT_TYPE_PARAM } from 'web-client/utilities/video/types';
import { FALLBACK_BITS_ACTIONS as BITS_ACTIONS_CONFIG } from 'web-client/utilities/bits/constants-config';

export const ROOT_VIDEO_NAMESPACE = 'http://api.twitch.tv/kraken';

/**
 Filter a collection of items starting with the first that returns true for
 the callback argument and optionally limit the results.
 @method filterFrom
 @param { Array } collection is the array to be filtered
 @param { Function } callback returns true for the first item
 @param { Number } [limit=null] optional limit for result length
 */

function filterFrom(collection, callback, limit=null) {
  let result = [];
  let i;
  for (i=0;i<collection.length;i++) {
    if (callback(collection[i], i)) {
      break;
    }
  }
  for (i;i<collection.length;i++) {
    result.push(collection[i]);
    if (limit && result.length >= limit) {
      break;
    }
  }
  return result;
}

export default function(server, namespace = ROOT_VIDEO_NAMESPACE) {
  server.namespace = namespace;

  server.get('/channels/:channel/follows', function(schema, request) {
    const PAGESIZE = 24;
    let { offset, limit } = pageParams(request);
    limit = limit || PAGESIZE;
    let followers = schema.followers.all();
    let _total = followers.models.length;
    let serialized = serialize(server, followers);
    serialized.follows = serialized.follows.slice(offset, offset + limit);

    let channel = request.params.channel;

    return assign(serialized, {
      _total,
      _links: {
        self:  `https://api.twitch.tv/kraken/channels/${channel}/follows?cursor=1465919583434589000&direction=DESC&limit=${limit}&offset=${offset}`,
        next:  `https://api.twitch.tv/kraken/channels/${channel}/follows?cursor=1465919583434589000&direction=DESC&limit=${limit}&offset=${offset + limit}`
      }
    });
  });

  server.get('/channels/:channel_id/community', function() {
    return {};
  }, 200);

  server.get('/communities/top', function() {
    return {
      _cursor: '',
      _total: 1,
      communities: [{
        _id: 'abcdefg',
        avatar_image_url: '',
        channels: 1,
        name: 'foobar',
        viewers: 12345
      }]
    };
  }, 200);

  server.get('/communities', function() {
    return {
      _id: '123',
      avatar_image_url: '',
      cover_image_url: '',
      description: '',
      description_html: '',
      language: 'EN',
      name: 'Super-Mario-Maker',
      owner_id: '12345',
      rules: '',
      rules_html: '',
      summary: ''
    };
  }, 200);

  server.get('/communities/:community_id/permissions', function() {
    return {
      edit: true,
      ban: true,
      timeout: true
    };
  }, 200);

  server.get('/communities/:community_id/bans', function() {
    return {
      _cursor: '',
      banned_users: []
    };
  }, 200);

  server.get('/communities/:community_id/moderators', function() {
    return {
      moderators: []
    };
  }, 200);

  server.get('/channels/:channel_id/ads/settings', function(schema, request) {
    return {
      channel_id: request.params.channel_id,
      frequency: 480,
      max_break_length: 300
    };
  }, 200);

  // TODO: remove after new commercial endpoints have been added to /api namespace in web/web
  server.post('/channels/:channel/commercial', function() {
    return;
  });

  server.get('/channels/:channel/videos', function(schema, request) {
    let broadcastType = request.queryParams.broadcast_type;
    if (!broadcastType) {
      // web-client sends 'broadcasts=true' for archive (past broadcasts) and nothing for highlights
      broadcastType = request.queryParams.broadcasts ? ARCHIVE_TYPE_PARAM : HIGHLIGHT_TYPE_PARAM;
    }

    let channel = request.params.channel;
    let broadcastTypes = broadcastType.split(',');
    return schema.videos.all().filter(video => {
      return broadcastTypes.indexOf(video.broadcast_type) !== -1 && video.channel.attrs.name === channel;
    });
  });

  server.get('/chat/:channel/badges', function (schema, request) {
    let channelChatBadge = schema.db.channelChatBadges.where({ name: request.params.channel })[0];
    return channelChatBadge;
  });

  server.get('/channels/:channel/collections', function(schema, request) {
    let { limit } = request.queryParams;
    let collections = schema.videoPlaylists.where((playlist) => parseInt(playlist.owner.id) === parseInt(request.params.channel)).models;

    if(limit) {
      collections = collections.slice(0, limit);
    }
    //Return a fake cursor so paginator doesn't think there are no more records
    return { _cursor: 'fake_cursor', collections };
  });

  server.post('/channels/:channel/collections', function(schema, request) {
    let body = parseQueryParams(request.requestBody);
    let firstUser = schema.users.first();
    if (!body.owner) {
      body.owner = { id: firstUser.id, name: firstUser.login };
    }

    return schema.videoPlaylists.create(body);
  });


  server.get('/channel', {
    mature: null,
    status: 'Twitch Stream',
    display_name: 'Twitch',
    game: 'Dota 2',
    _id: 999999999,
    name: 'twitch',
    created_at: '2016-07-08T20:14:09Z',
    updated_at: '2016-10-31T17:32:23Z',
    logo: 'https://static-cdn.jtvnw.net/jtv_user_pictures/twitch-profile_image-e73ff99aa2e7e872-300x300.png',
    banner: null,
    video_banner: null,
    background: null,
    url: 'https://www.twitch.tv/twitch',
    _links: {
      self: 'https://api.twitch.tv/kraken/channels/twitch',
      follows: 'https://api.twitch.tv/kraken/channels/twitch/follows',
      commercial: 'https://api.twitch.tv/kraken/channels/twitch/commercial',
      stream_key: 'https://api.twitch.tv/kraken/channels/twitch/stream_key',
      chat: 'https://api.twitch.tv/kraken/chat/twitch',
      subscriptions: 'https://api.twitch.tv/kraken/channels/twitch/subscriptions',
      editors: 'https://api.twitch.tv/kraken/channels/twitch/editors',
      videos: 'https://api.twitch.tv/kraken/channels/twitch/videos'
    },
    teams: [],
    email: 'testemail@justin.tv',
    stream_key: 'live_123abc456def'
  });

  server.delete('/channels/:channel/stream_key', {
    mature: null,
    status: 'Twitch Stream',
    display_name: 'Twitch',
    game: 'Dota 2',
    _id: 999999999,
    name: 'twitch',
    created_at: '2016-07-08T20:14:09Z',
    updated_at: '2016-10-31T17:32:23Z',
    logo: 'https://static-cdn.jtvnw.net/jtv_user_pictures/twitch-profile_image-e73ff99aa2e7e872-300x300.png',
    banner: null,
    video_banner: null,
    background: null,
    url: 'https://www.twitch.tv/twitch',
    _links: {
      self: 'https://api.twitch.tv/kraken/channels/twitch',
      follows: 'https://api.twitch.tv/kraken/channels/twitch/follows',
      commercial: 'https://api.twitch.tv/kraken/channels/twitch/commercial',
      stream_key: 'https://api.twitch.tv/kraken/channels/twitch/stream_key',
      chat: 'https://api.twitch.tv/kraken/chat/twitch',
      subscriptions: 'https://api.twitch.tv/kraken/channels/twitch/subscriptions',
      editors: 'https://api.twitch.tv/kraken/channels/twitch/editors',
      videos: 'https://api.twitch.tv/kraken/channels/twitch/videos'
    },
    teams: [],
    email: 'testemail@justin.tv',
    stream_key: 'live_123abc999ggg'
  });

  server.get('/channels/similar', function({channels}) {
    return {similar_channels: channels.all().models.filter((channel) => { return channel.name === 'similar'; })};
  });

  server.get('/channels/favorite', function({channels}) {
    return {favorite_channels: channels.all().models.filter((channel) => { return channel.name === 'favorite'; })};
  });

  server.get('/channels/:channel', function(schema, request) {
    let name = request.params.channel;
    let channel = schema.db.channelEmberData.where({ name })[0];

    if (!channel || channel.name === '404') {
      return new Mirage.Response(404, {}, {
        status: 404,
        error: `channel '${name}' not found `
      });
    }

    return channel;
  });

  server.get('/game/:game', function(schema, request) {
    let name = decodeURIComponent(request.params.game);
    let game = schema.db.games.where(function(g){
      return g.name.toLowerCase() === name.toLowerCase();
    })[0];

    if (!game || game.name === '404') {
      return new Mirage.Response(404, {}, {
        error: 'Not Found',
        message: 'No game of that name found',
        status: 404
      });
    }

    return {
      game,
      _links: {
        self: `https://api.twitch.tv/kraken/game/${name}`
      }
    };
  });

  server.get('/search/games', function(schema, request) {
    let games = schema.db.games;
    let query = request.queryParams.q || 'Creative';
    return {
      games,
      _links: {
        self: `https://api.twitch.tv/kraken/search/games?q=${query}&type=suggest`
      }
    };
  });

  server.get('/feed/:channel/posts', function(schema, request) {
    // TODO Return Mirage.Response error when the user is opted out of feed
    // return new Mirage.Response(403, {}, {
    //   status: 403,
    //   error: 'Forbidden',
    //   message: 'Channel feed is disabled'
    // });
    let posts = schema.db.posts;

    let filter = (item, index) => index === 0;
    let cursor = request.queryParams.cursor;

    if (cursor) {
      // when a cursor is present the first item should be the item following
      // the item matching the cursor (by id)
      filter = (item, index) => index > 0 && posts[index-1].id === cursor;
    }

    let limit = null;

    if (request.queryParams.limit) {
       limit = parseInt(request.queryParams.limit, 10);
    }

    let limitedPosts = filterFrom(posts, filter, limit);

    return {
      _cursor: limitedPosts.length ? limitedPosts[0].id : '',
      _total: posts.length,
      posts: limitedPosts
    };
  }, 200);

  server.get('/feed/posts', function() {
    return {};
  }, 200);

  server.post('/feed/:channel/posts', function(schema, request) {
    let params = parseQueryParams(request.requestBody);
    params.body = params.content;
    let post = schema.posts.create(params);

    return post;
  }),

  server.delete('/feed/:channel/posts/:id', function(schema, request) {
    let posts = schema.db.posts;
    let postId = request.params.id;
    posts.remove(postId);

    return { id: postId, deleted: true };
  }, 200),

  server.post('/feed/:channel/posts/:post_id/comments', function(schema, request) {
    let params = parseQueryParams(request.requestBody);
    params.body = params.content;
    params.permissions = { can_delete: true };
    let comment = schema.comments.create(params);

    return comment;
  }),

  server.delete('/feed/:channel/posts/:post_id/comments/:comment_id', function(schema, request) {
    let comments = schema.db.comments;
    let commentId = request.params.comment_id;
    comments.remove(commentId);

    return { id: commentId, deleted: true };
  }, 200),

  server.post('/feed/:channel/posts/:post_id/comments/:comment_id/reactions', function() {
    return { id: 1 };
  }),

  server.delete('/feed/:channel/posts/:post_id/comments/:comment_id/reactions', function() {
    return { id: 1 };
  }, 200),

  server.post('/feed/:channel/posts/:post_id/report', function() {
    return true;
  });

  server.get('/feed/:channel/posts/permissions', function() {
    return {
      can_reply: false,
      can_moderate: true,
      can_delete: true
    };
  }, 200);

  server.get('/beta/streams/random', function(schema) {
    return schema.streams.all();
  });

  server.get('streams/recommended/available', function() {
    return { recommended: [] };
  });

  server.get('recommendations/videos/trending', function(schema) {
    return schema.trendingVideos.find(1);
  });

  server.get('recommendations/videos/releases/games', function(schema, request) {
    let serializedGameNewReleases = [];
    let gameNewReleaseSerializer = server.serializerOrRegistry.serializerFor('game-new-release');
    schema.gameNewReleases.all().models.forEach((gameNewRelease) => {
      serializedGameNewReleases.push(gameNewReleaseSerializer.serialize(gameNewRelease, request));
    });
    return {new_releases: serializedGameNewReleases};
  });

  server.get('/streams/featured', function (schema) {
    let featured = [];
    schema.featuredStreams.all().models.forEach((fstream) => {
      featured.push(assign(assign({}, fstream.attrs), {stream: serialize(server, fstream.stream).stream}));
    });

    return {
      featured,
      _links: {
        next: "http://api.twitch.tv/kraken/streams/featured?limit=2&offset=2",
        self: "http://api.twitch.tv/kraken/streams/featured?limit=2&offset=0"
      }
    };
  });

  server.get('/streams/:channel', function (schema, request) {
    let channel = schema.db.channelStreams.where({ name: request.params.channel })[0];
    return channel;
  });

  server.get('search/users', function (schema, request) {
    let name = request.queryParams.q;
    let users = schema.db.users.filter(user => user.name.indexOf(name) !== -1);

    return {
      _total: users.length,
      users
    };
  });

  server.get('/games/:game/communities', function (schema, request) {
    let game = request.params.game;
    let communities = schema.db.communities.where({ game });
    return {
      communities,
      _total: communities.length,
      _links: {
        next: "http://api.twitch.tv/kraken/streams/featured?limit=2&offset=2",
        self: "http://api.twitch.tv/kraken/streams/featured?limit=2&offset=0"
      }
    };
  });

  server.get('/games/:game/communities/:hashtag', function () {
    return new Mirage.Response(404, {}, {});
  });

  server.get('/streams/communities/:hashtag', function () {
    return new Mirage.Response(404, {}, {});
  });

  server.get('/games/top', function (schema) {
    let games = schema.db.games.where({ _is_featured: false });
    let top = games.map(function(game) {
      return {
        channels: game._channels,
        viewers: game._viewers,
        game: omit(game, '_channels', '_viewers', '_is_featured')
      };
    });

    return {
      top,
      _total: games.length,
      _links: {
        next: "http://api.twitch.tv/kraken/games/top?limit=2&offset=2",
        self: "http://api.twitch.tv/kraken/games/top?limit=2&offset=0"
      }
    };
  });

  server.get('/games/:game/settings', function () {
    return {
      details_enabled: true
    };
  });

  server.get('/hosters', function({users}) {
    return { hosters: users.all().models.map((user) => ({ host_login: user.name, host_id: user._id })) };
  });

  server.get('/autohost/status', function() {
    return { status: { is_autohosting: false } };
  });

  server.get('/autohost/settings', function({autohostSettings}) {
    return { settings: autohostSettings.first() };
  });

  server.put('/autohost/settings', function({autohostSettings}, params) {
    let settings = autohostSettings.first();
    let newSettings = URI.parseQuery(params.requestBody);
    newSettings.enabled = newSettings.enabled === 'true';
    newSettings.team_host = newSettings.team_host === 'true';
    newSettings.recommended_host = newSettings.recommended_host === 'true';

    return { settings: settings.update(newSettings) };
  });

  server.get('/autohost/list', function({channels}) {
    return { targets: channels.all().models
      .filter((channel) => { return channel.name === 'autohost_target'; })
      .sort((a,b) => a._id > b._id) };
  });

  server.put('/autohost/list', function({channels}, params) {
    let targets = URI.parseQuery(params.requestBody).targets;
    if (targets.length === 0){
      return { targets: [] };
    }

    let targetIDs = targets.split(',');
    let allChannels = channels.all().models;
    let targetChannels = targetIDs.map((id) => {
      return allChannels.find((channel) => `${channel._id}` === id);
    });

    return { targets: targetChannels };
  });

  server.delete('/autohost/list', function() {
    return { targets: [] };
  });

  server.get('/autohost/list/added', function({channels}) {
    return {added_me: channels.all().models.filter((channel) => { return channel.name === 'autohosted_by_channel'; })};
  });

  server.get('/ingest/bitrate', function(){
    return {
      Channel: 'twitch',
      Metric: 'bitrate',
      Results: []
    };
  });

  server.get('/channels/:channel_id/ingest/health', function () {
    return {
      health_code: 101,
      health_reason_codes: [1000]
    };
  });

  server.get('/broadcasts/:broadcast_id/clips/count', {
    count: 100
  });

  server.get('/bits/actions', function() {
    return BITS_ACTIONS_CONFIG;
  });

  server.get('embed', function () {
    return {
      request_url : 'https://clips.twitch.tv/proleaguecsgo/NiceOwlSMOrc',
      type : 'video',
      title : 'LIVE: G2  vs. Dignitas - ESL Pro League | pro.eslgaming.com","author_name":"ProLeagueCSGO',
      thumbnail_url : 'https://clips-media-assets.twitch.tv/23158222624-offset-15622-preview.jpg',
      html : '\u003ciframe src=\"https://clips.twitch.tv/embed?clip=proleaguecsgo/NiceOwlSMOrc\u0026amp;autoplay=true\" width=\"500\" height=\"281\" frameborder=\"0\" scrolling=\"no\" allowfullscreen\u003e\u003c/iframe\u003e',
      provider_name : 'Twitch',
      created_at : '2016-09-13T20:50:37Z',
      game : 'Counter-Strike: Global Offensive',
      video_length : '30',
      twitch_type : 'clip'
    };
  });

  server.namespace = undefined;
}
