import { parse } from 'url';
import request from 'superagent';
import 'superagent-bluebird-promise';
import debuglog from 'debug';
import urlMatch from './url';

const debug = debuglog('combine.fm:xbox');

if (!process.env.XBOX_CLIENT_ID || !process.env.XBOX_CLIENT_SECRET) {
  debug('XBOX_CLIENT_ID and XBOX_CLIENT_SECRET environment variables not found, deactivating Xbox Music.');
}

const credentials = {
  clientId: process.env.XBOX_CLIENT_ID,
  clientSecret: process.env.XBOX_CLIENT_SECRET,
};

const apiRoot = 'https://music.xboxlive.com/1/content';

function* getAccessToken() {
  const authUrl = 'https://login.live.com/accesstoken.srf';
  const scope = 'app.music.xboxlive.com';
  const grantType = 'client_credentials';

  const data = {
    client_id: credentials.clientId,
    client_secret: credentials.clientSecret,
    scope,
    grant_type: grantType,
  };
  const result = yield request.post(authUrl)
    .timeout(10000)
    .send(data)
    .set('Content-type', 'application/x-www-form-urlencoded')
    .promise();
  return result.body.access_token;
}

function formatResponse(match) {
  const item = {
    service: 'xbox',
    type: match.Album ? 'track' : 'album',
    id: match.Id,
    name: match.Name,
    streamUrl: match.Link,
    purchaseUrl: null,
    artwork: {
      small: `${match.ImageUrl.replace('http://', 'https://')}&w=250&h=250`,
      large: `${match.ImageUrl.replace('http://', 'https://')}&w=500&h=500`,
    },
    artist: {
      name: match.Artists[0].Artist.Name,
    },
  };
  if (match.Album) {
    item.album = { name: match.Album.Name };
  }
  return item;
}

function* apiCall(path) {
  const accessToken = yield getAccessToken();
  return request.get(apiRoot + path).timeout(10000).set('Authorization', `Bearer ${accessToken}`).promise();
}

export function* lookupId(id, type) {
  const path = `/${id}/lookup`;
  const apiType = `${type.charAt(0).toUpperCase() + type.substr(1)}s`;
  try {
    const result = yield apiCall(path);
    return formatResponse(result.body[apiType].Items[0]);
  } catch (e) {
    if (e.status !== 404) {
      debug(e.body);
    }
    return { service: 'xbox' };
  }
}

export function* parseUrl(url) {
  const parsed = parse(url);
  const parts = parsed.path.split('/');
  const type = parts[1];
  const idMatches = parts[4].match(/bz.[\w-]+/);
  const id = idMatches[0].replace('bz.', 'music.');
  if (!id) {
    return false;
  }
  return yield lookupId(id, type);
}

function exactMatch(item, artist, haystack) {
    // try to find exact match
  return haystack.find((entry) => {
    if (entry.Name === item && entry.Artists[0].Artist.Name === artist) {
      return entry;
    }
    return false;
  });
}

function looseMatch(item, artist, haystack) {
    // try to find exact match
  return haystack.find((entry) => {
    if (entry.Name.indexOf(item) >= 0 && entry.Artists[0].Artist.Name.indexOf(artist) >= 0) {
      return entry;
    }
    return false;
  });
}

export function* search(data) {
  function cleanParam(str) {
    return str.replace(/[:?&()[\]]+/g, '');
  }
  let query;
  const type = data.type;

  if (type === 'album') {
    query = `${cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&')))} ${cleanParam(data.name)}`;
  } else if (type === 'track') {
    query = `${cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&')))} ${cleanParam(data.name)}`;
  }

  const name = data.name;
  const path = `/music/search?q=${encodeURIComponent(query.trim())}&filters=${type}s`;
  try {
    const result = yield apiCall(path);

    const apiType = `${type.charAt(0).toUpperCase() + type.substr(1)}s`;

    let match = exactMatch(name, data.artist.name, result.body[apiType].Items, type);
    if (!match) {
      match = looseMatch(name, data.artist.name, result.body[apiType].Items, type);
    }

    if (match) {
      return formatResponse(match);
    }
  } catch (err) {
    return { service: 'xbox' };
  }
  return { service: 'xbox' };
}

export const id = 'xbox';
export const match = urlMatch;