"use strict";



//  I M P O R T S

import got from "got";
import html from "choo/html";

//  U T I L S

import apiPage from "~view/api";
import fetchMetadata from "~helper/fetch-metadata";
import lbrytvAPI from "~helper/lbrytv-sdk";
import { generateGitHubFeed } from "~helper/github";
import messageSlack from "~helper/slack";
import { URL } from "url";

const githubAppId = process.env.GITHUB_APP_ID;
const githubAppSecret = process.env.GITHUB_APP_SECRET;

// const githubAppId = process.env.GITHUB_APP_ID_TEST;
// const githubAppSecret = process.env.GITHUB_APP_SECRET_TEST;



//  P R O G R A M

export default async(socket, action) => {
  if (typeof socket !== "object" && typeof action !== "object")
    return;

  switch(true) {
    case action.message === "auth me with github":
      getGitHubUserToken(socket);
      break;

    case action.message === "verify github token":
      verifyGitHubToken(action, socket);
      break;

    case action.message === "fetch metadata":
      fetchMetadata(action, socket);
      break;

    case action.message === "landed on homepage":
      generateGitHubFeed(result => {
        send(socket, {
          html: result,
          message: "updated html",
          selector: "#github-feed"
        });
      });
      break;

    case action.message === "landed on playground":
      generateContent(1, result => {
        send(socket, {
          html: result,
          message: "updated html",
          selector: "#playground-loader"
        });
      });
      break;

    case action.message === "request for playground, example 1":
      generateContent(1, result => {
        send(socket, {
          html: result,
          message: "updated html",
          selector: "#playground-loader"
        });
      });
      break;

    case action.message === "request for playground, example 2":
      generateMemeCreator(socket);
      break;

    case action.message === "request for playground, example 3":
      generateContent(3, result => {
        send(socket, {
          html: result,
          message: "updated html",
          selector: "#playground-loader"
        });
      });
      break;

    case action.message === "subscribe":
      newsletterSubscribe(action, socket);
      break;


    case action.message === "view different documentation version":
      send(socket, {
        element: "div",
        html: await apiPage({
          params: {
            wildcard: action.version.split("-")[0]
          },
          tag: action.version.split("-")[1]
        }),
        message: "replace html",
        parentElement: "main",
        selector: ".__slate"
      });
      break;

    default:
      break;
  }
};



//  H E L P E R S

function generateContent(exampleNumber, displayTrendingContent) {
  if (exampleNumber === 1) {
    return lbrytvAPI.getTrending()
      .then(response => {
        const renderedContentCollection = [];
        const urlsToResolve = [];

        response.forEach(r => {
          urlsToResolve.push(r.canonical_url);
        });
        lbrytvAPI.resolve(urlsToResolve)
          .then(resolveResponse => {
            if (resolveResponse !== null) {
              const responses = Object.values(resolveResponse);

              for (const r in responses) {
                const part = responses[r];

                if (part.value && part.value.thumbnail.url) {
                  renderedContentCollection.push(`
                  <section class="playground-content__trend">
                    <figure
                      class="media__thumb"
                      data-action="choose claim"
                      data-claim-id="${part.claim_id}"
                      data-name=${part.name}
                      style="background-image: url(${makeImageSourceSecure(part.value.thumbnail.url)})">
                    </figure>
      
                    <div class="media__title">
                      ${part.value.title || "Untitled"}
                    </div>
      
                    <div class="media__subtitle">
                      ${part.signing_channel ? part.signing_channel.name : "Anon"}
                    </div>
                  </section>
                `);
                }
              }
            }
            renderedContentCollection.push(`
            <script>
              document.getElementById("playground-example-description").innerHTML = document.querySelector("[data-action='playground, example 1']").dataset.description
            </script>
          `);
            displayTrendingContent(renderedContentCollection.join(""));
          })
          .catch(error => {
            console.error(error);
          });
      });
  }

  if (exampleNumber === 3) {
    const approvedUrls = [
      "LBRY#3db81c073f82fd1bb670c65f526faea3b8546720",
      "correlation-can-imply-causation#173412f5b1b7aa63a752e8832406aafd9f1ecb4e",
      "thanos-is-the-protagonist-how-infinity#2a7f5db2678177435b1dee6c9e38e035ead450b6",
      "epic-arcade-mode-duos-nickatnyte-molt#d81bac6d49b1f92e58c37a5f633a27a45b43405e",
      "political-correctness-a-force-for-good-a#b4668c0bd096317b44c40738c099b6618095e75f",
      "10-secrets-hidden-inside-famous-logos#007789cc45cbb4255cf02ba77cbf84ca8e3d7561",
      "ever-wonder-how-bitcoin-and-other#1ac47b8b3def40a25850dc726a09ce23d09e7009",
      "bankrupt-pan-am#784b3c215a6f06b663fc1aa292bcb19f29c489bb",
      "minecraft-in-real-life-iron-man#758dd6497cdfc401ae1f25984738d024d47b50af",
      "ethan-shows-kyle-warframe-skyvault#8a7401b88d5ed0376d98f16808194d4dcb05b284"
    ];
    const renderedContentCollection = [];

    lbrytvAPI.resolve(approvedUrls)
      .then(resolveResponse => {
        if (resolveResponse !== null) {
          const responses = Object.values(resolveResponse);

          for (const r in responses) {
            const part = responses[r];

            if (part.value && part.value.thumbnail.url) {
              renderedContentCollection.push(`
                  <section class="playground-content__trend">
                    <figure
                      class="media__thumb"
                      data-action="choose claim"
                      data-claim-id="${part.claim_id}"
                      data-name=${part.name}
                      style="background-image: url(${makeImageSourceSecure(part.value.thumbnail.url)})">
                    </figure>
      
                    <div class="media__title">
                      ${part.value.title || "Untitled"}
                    </div>
      
                    <div class="media__subtitle">
                      ${part.signing_channel ? part.signing_channel.name : "Anon"}
                    </div>
                  </section>
                `);
            }
          }
        }
        renderedContentCollection.push(`
            <script>
              document.getElementById("playground-example-description").innerHTML = document.querySelector("[data-action='playground, example 3']").dataset.description
            </script>
          `);
        displayTrendingContent(renderedContentCollection.join(""));
      })
      .catch(error => {
        console.error(error);
      });
  }
}

function generateMemeCreator(socket) {
  const images = [
    {
      alt: "Carl Sagan",
      // src: "https://spee.ch/4f6b953e605a602434246743fd246d3e1fd4f5fd/carlsagan2.jpg"
      src: "/assets/media/images/carlsagan2.jpg"
    },
    {
      alt: "Doge",
      // src: "https://spee.ch/2f90f2d91441a4d33d3d4eb82bdfc4c56ec742c7/doge-meme.jpg"
      src: "/assets/media/images/doge-meme.jpg"
    },
    {
      alt: "LBRY Logo With Green Background",
      // src: "https://spee.ch/40ac6818bbac87a208722bf4467653341d460908/lbry-green.png"
      src: "/assets/media/images/lbry-green.png"
    }
  ];

  const memePlaceholderData = {
    bottomLine: {
      placeholder: "Top line",
      value: "that I made"
    },
    description: {
      placeholder: "Description",
      value: "Check out this image I published to LBRY via lbry.tech"
    },
    topLine: {
      placeholder: "Top line",
      value: "This is an example meme"
    },
    title: {
      placeholder: "Title",
      value: "Dank Meme Supreme da Cheese"
    }
  };

  const renderedImages = [];

  for (const image of images)
    renderedImages.push(`<img alt="${image.alt}" class="playground-content__meme__canvas__thumbnail" src="${image.src}"/>`);

  const memeCreator = html`
    <div class="playground-content__meme__canvas">
      <img alt="Base image for LBRY meme creator" id="base-image" style="height: 0; position: absolute; visibility: hidden;"/>
      <canvas id="meme-canvas" height="600" width="800">Unfortunately, it looks like canvas is <strong>not supported</strong> in your browser</canvas>

      ${renderedImages}
    </div>

    <form class="playground-content__meme__editor">
      <fieldset>
        <legend>Image Text</legend>

        <fieldset-section>
          <label for="meme-top-line">Top line</label>
          <input id="meme-top-line" name="meme-top-line" placeholder="${memePlaceholderData.topLine.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.topLine.value}" required/>
        </fieldset-section>

        <fieldset-section>
          <label for="meme-bottom-line">Bottom line</label>
          <input id="meme-bottom-line" name="meme-bottom-line" placeholder="${memePlaceholderData.bottomLine.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.bottomLine.value}" required/>
        </fieldset-section>
      </fieldset>

      <fieldset>
        <legend>Metadata</legend>

        <fieldset-section>
          <label for="meme-title">Title</label>
          <input id="meme-title" name="meme-title" placeholder="${memePlaceholderData.title.placeholder}" spellcheck="false" type="text" value="${memePlaceholderData.title.value}" required/>
        </fieldset-section>

        <fieldset-section>
          <label for="meme-description">Description</label>
          <textarea id="meme-description" name="meme-description" placeholder="${memePlaceholderData.description.placeholder}" spellcheck="false" type="text" required>${memePlaceholderData.description.value}</textarea>
        </fieldset-section>

        <fieldset-section>
          <label for="meme-language">Language</label>
          <select id="meme-language" name="meme-language">
            <option value="ar">Arabic</option>
            <option value="zh">Chinese (Mandarin)</option>
            <option value="en">English</option>
            <option value="fr">French</option>
            <option value="de">German</option>
            <option value="it">Italian</option>
            <option value="jp">Japanese</option>
            <option value="ru">Russian</option>
            <option value="es">Spanish</option>
            <option value="">Not specified</option>
          </select>
        </fieldset-section>

        <fieldset-section>
          <label for="meme-license">License</label>
          <select id="meme-license" name="meme-license" required>
            <option value="Public Domain">Public Domain</option>
            <option value="Creative Commons Attribution 4.0 International">Creative Commons Attribution 4.0 International</option>
            <option value="Creative Commons Attribution-ShareAlike 4.0 International">Creative Commons Attribution-ShareAlike 4.0 International</option>
            <option value="Creative Commons Attribution-NoDerivatives 4.0 International">Creative Commons Attribution-NoDerivatives 4.0 International</option>
            <option value="Creative Commons Attribution-NonCommercial 4.0 International">Creative Commons Attribution-NonCommercial 4.0 International</option>
            <option value="Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</option>
            <option value="Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International</option>
            <option value="None">None</option>
          </select>
        </fieldset-section>

        <fieldset-section>
          <checkbox-element>
            <input id="meme-nsfw-flag" name="nsfw" type="checkbox">
            <label for="meme-nsfw-flag">NSFW</label>
            <checkbox-toggle/>
          </checkbox-element>

          <button data-action="upload image" class="button" type="button">Submit</button>
        </fieldset-section>
      </fieldset>
    </form>
  `;

  return send(socket, {
    example: 2,
    html: memeCreator,
    message: "updated html",
    selector: "#playground-loader"
  });
}

function getGitHubUserToken(socket) {
  send(socket, {
    message: "redirect",
    url: `https://github.com/login/oauth/authorize?client_id=${githubAppId}&scope=public_repo,user:email`
  });
}

function makeImageSourceSecure(url) {
  if (!url || !url.length)
    return url;

  const originalUrl = new URL(url);

  if (originalUrl.protocol !== "https")
    return `https://${originalUrl.host}${originalUrl.pathname}`;

  return originalUrl.href;
}

async function newsletterSubscribe(data, socket) {
  const email = data.email;

  if (!validateEmail(email)) {
    send(socket, {
      class: "error",
      html: "Your email address is invalid",
      message: "updated html",
      selector: "#emailMessage"
    });
  }

  try {
    await got.post(`https://api.lbry.com/list/subscribe?email=${encodeURIComponent(email)}&tag=developer`);

    return send(socket, {
      html: "Thank you! Please confirm subscription in your inbox.",
      message: "updated html",
      selector: "#emailMessage"
    });
  } catch(error) {
    const response = JSON.parse(error.body);

    if (!response.success) {
      messageSlack({
        message: `via ${email}: ${response.error}`,
        title: "NEWSLETTER ERROR"
      });

      return send(socket, {
        class: "error",
        html: response.error,
        message: "updated html",
        selector: "#emailMessage"
      });
    }

    messageSlack({
      message: `via ${email} (strange error): ${response.error}`,
      title: "NEWSLETTER ERROR"
    });

    return send(socket, {
      class: "error",
      html: "Something is terribly wrong",
      message: "updated html",
      selector: "#emailMessage"
    });
  }
}

export function send(transport, data) {
  return transport.send(JSON.stringify(data));
}

function validateEmail(email) {
  const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\\.,;:\s@"]{2,})$/i;
  return emailRegex.test(String(email)); // eslint-disable-line padding-line-between-statements
}

async function verifyGitHubToken(data, socket) {
  const code = data.code;

  try {
    const result = await got.post(`https://github.com/login/oauth/access_token?client_id=${githubAppId}&client_secret=${githubAppSecret}&code=${code}`, { json: true });

    const response = {
      address: data.address,
      code: result.body.access_token
    };

    return send(socket, {
      data: response,
      message: "github token status"
    });
  } catch(verificationError) {
    console.log(verificationError.body); // eslint-disable-line no-console

    return send(socket, {
      details: verificationError.body,
      message: "notification",
      type: "error"
    });
  }
}
