/** @module root/router */
'use strict';
// vim: set ts=2 sw=2 et tw=80:

const express = require('express');
const router = express.Router();

const mongoose = require('mongoose');
const Favorite = mongoose.model('Favorite');
const fetch = require('node-fetch');
const querystring = require('querystring');
const promiseAny = require('promise-any');
const eventBus = require('../../pubsub');
const fetch64 = require('fetch-base64');

router.get('/', (req, res) => {
  if (req.query.access_token) {
    req.app.locals.imgur = req.query;
    res.redirect('/');
  } else {
    res.status(200, {'Content-Type': 'text/html'});
    res.end(`<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
    <script>
      console.log(window.location.href);
      if (window.location.href.indexOf("#access") != -1) {
        window.location.href = window.location.href.replace("#access",
          "?access");
      }
    </script></body></html>`);
  }
});

async function fetchImgur(req, res, method, url, body) {
  const endpoint = 'https://api.imgur.com/3';

  const response = await fetch(endpoint + url, {
    method: method,
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization' : 'Bearer ' + req.app.locals.imgur.access_token
    },
    body: body ? querystring.stringify(body) : undefined
  });

  const json = await response.json();

  if (json.status == 409 && url.match(/follow\/tag/)) {
    return {};
  }

  if (Math.floor(json.status / 100) != 2) {
    res.status(json.status).json(json);
    return false;
  }

  return json;
}

router.post('/ordeal', async (req, res) => {
  try {
    if ((!req.body.replace && (!req.body.name || !req.body.album)) ||
      (req.body.replace && (!req.body.name || !req.body.oldName))) {
      res.status(400).json({ error: "Malformed ordeal request" });
      return;
    }

    const ordealResponse = { ordealSuccess: true };

    const uploadData = {
      image: req.body.dataURL.substring('data:image/png;base64,'.length),
      type: 'base64',
      title: req.body.name,
      name: req.body.name + '.png',
    };

    const uploadJson = await fetchImgur(req, res, 'POST', '/upload', uploadData);
    if (!uploadJson) {
      return;
    }

    const imageId = uploadJson.data.id;

    const albumData = {
      'ids[]': imageId,
    };

    if (!req.body.replace) {
      if (req.body.album) {
        albumData.title = req.body.album;
      }

      const albumJson = await fetchImgur(req, res, 'POST', '/album', albumData);
      if (!albumJson) {
        return;
      }

      if (req.body.favorites) {
        if (!await fetchImgur(req, res, 'POST', '/album/' + albumJson.data.id +
          '/favorite', {})) {
          return;
        }
      }
    } else {
      req.body.album = undefined;

      const submissions = await fetchImgur(req, res, 'GET',
        '/account/me/submissions');

      if (!submissions) {
        return;
      }

      const submission = submissions.data
        .filter(e => !e.images && e.in_gallery &&
          e.title == req.body.oldName)[0];

      if (!submission) {
        res.status(404).json({ error: "No image in submissions found" });
        return;
      }

      console.log('submission', submission.id, submission.title);

      const result = {};
      result.image = submission;
      ordealResponse.views = submission.views;
      ordealResponse.votes = {};
      ordealResponse.votes.ups = submission.ups;
      ordealResponse.votes.downs = submission.downs;

      const albumIds = await fetchImgur(req, res, 'GET',
        '/account/me/albums/ids');

      if (!albumIds) {
        return;
      }

      console.log('albumIds', albumIds.data.join(','));

      let reject = false;
      const promises = [];
      for (const albumId of albumIds.data) {
        promises.push(new Promise(async (res, rej) => {
          if (reject) {
            return reject;
          }

          const images = await fetchImgur(req, res, 'GET', '/album/' +
            albumId + '/images');

          if (!images || reject) {
            rej();
            return;
          }

          console.log('album', albumId, 'images', images.data.map(e => e.id));

          const image = images.data.filter(e => e.id == result.image.id)[0];


          if (!image || reject) {
            rej();
            return;
          }

          reject = true;
          console.log('the album', albumId, 'image', image.id);
          res(albumId);
        }));
      }

      try {
        result.albumId = await promiseAny(promises);
      } catch(_) {
        res.status(400).json({ error: "Image not found in any album" });
        return;
      }

      if (!await fetchImgur(req, res, 'DELETE', '/image/' + result.image.id)) {
        return;
      }

      if (!await fetchImgur(req, res, 'PUT', '/album/' +
        result.albumId + '/add', { 'ids[]': uploadJson.data.id })) {
        return;
      }
    }

    if (!await fetchImgur(req, res, 'POST', '/gallery/image/' +
      uploadJson.data.id, { title: req.body.name, tags: req.body.tags })) {
      return;
    }

    if (req.body.tags) {
      const tagsData = {
        'tags': req.body.tags
      };

      if (!await fetchImgur(req, res, 'POST', '/gallery/tags/' +
        uploadJson.data.id, tagsData)) {
        return;
      }

      for (const tag of req.body.tags.split(',')) {
        if (!await fetchImgur(req, res, 'POST', '/account/me/follow/tag/' + tag,
          {})) {
          return;
        }
      }
    }

    res.json(ordealResponse);
  } catch(e) {
    console.error(e);
    res.status(500).json({ error: e.toString() });
  }
});

router.post('/search', async (req, res) => {
  try {
    if (!req.body.name) {
      res.status(400).json({ error: 'Bad parameters for /imgur/search' });
      return;
    }

    const results = await fetchImgur(req, res, 'GET',
      '/gallery/search/time/top/1?q=' +
      encodeURIComponent(req.body.name) + '&q_type=png');

    if (!results) {
      return;
    }

    if (results.data.length == 0) {
      res.status(404).json({ error: 'No image found' });
      return;
    }

    let image = results.data[0];
    if (image.is_album) {
      image = image.images[0];
    }

    if (!await fetchImgur(req, res, 'POST', '/gallery/' + results.data[0].id +
      '/vote/up', {})) {
      return;
    }

    if (!await fetchImgur(req, res, 'POST', '/image/' + image.id + '/favorite',
      {})) {
      return;
    }

    const fetch64res = await fetch64.remote(image.link);

    const fav = {
      _id: mongoose.Types.ObjectId(),
      name: req.body.name,
      dataURL: fetch64res[1],
      bookmarked: false,
    };

    await new Favorite(fav).save();
    eventBus.emit('favorite.created', fav);

    res.json({ success: true });
  } catch(e) {
    console.error(e);
    res.status(500).json({ error: e.toString() });
  }
});

/** router for /root */
module.exports = router;
