/**
 * notion-enhancer: menu
 * (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
 * (https://notion-enhancer.github.io/) under the MIT license
 */

'use strict';

import { fmt, web, registry, components } from '../../api/index.mjs';
import { notifications } from './notifications.mjs';
import '../../dep/jscolor.min.js';

import '../../dep/markdown-it.min.js';
const md = markdownit({ linkify: true });

export const modComponents = {
  preview: (url) => web.html`<img
    class="mod-preview"
    src="${web.escape(url)}"
    alt=""
  >`,
  title: (title) => web.html`<h4 class="mod-title"><span>${web.escape(title)}</span></h4>`,
  version: (version) => web.html`<span class="mod-version">v${web.escape(version)}</span>`,
  tags: (tags) => {
    if (!tags.length) return '';
    return web.render(
      web.html`<p class="mod-tags"></p>`,
      tags.map((tag) => `#${web.escape(tag)}`).join(' ')
    );
  },
  description: (description) => {
    const $description = web.html`<p class="mod-description markdown-inline">
      ${md.renderInline(description)}
    </p>`;
    $description.querySelectorAll('a').forEach((a) => {
      a.target = '_blank';
    });
    return $description;
  },
  authors: (authors) => {
    const author = (author) => web.html`<a
      class="mod-author"
      href="${web.escape(author.homepage)}"
      target="_blank"
    >
      <img class="mod-author-avatar"
        src="${web.escape(author.avatar)}" alt="${web.escape(author.name)}'s avatar"
      > <span>${web.escape(author.name)}</span>
    </a>`;
    return web.render(web.html`<p class="mod-authors-container"></p>`, ...authors.map(author));
  },
  toggle: (label, checked) => {
    const $label = web.html`<label tabindex="0" class="toggle-label">
      <span>${web.escape(label)}</span>
    </label>`,
      $input = web.html`<input tabindex="-1" type="checkbox" class="toggle-check"
        ${checked ? 'checked' : ''}>`,
      $feature = web.html`<span class="toggle-box toggle-feature"></span>`;
    $label.addEventListener('keyup', (event) => {
      if (['Enter', ' '].includes(event.key)) $input.checked = !$input.checked;
    });
    return web.render($label, $input, $feature);
  },
};

export const options = {
  toggle: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      checked = await profileDB.get([mod.id, opt.key], opt.value),
      $toggle = modComponents.toggle(opt.label, checked),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = $toggle.children[0],
      $input = $toggle.children[1];
    if (opt.tooltip) {
      $label.prepend($tooltipIcon);
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    }
    $input.addEventListener('change', async (_event) => {
      await profileDB.set([mod.id, opt.key], $input.checked);
      notifications.onChange();
    });
    return $toggle;
  },

  select: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      value = await profileDB.get([mod.id, opt.key], opt.values[0]),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $options = opt.values.map(
        (option) => web.raw`<option
          class="select-option"
          value="${web.escape(option)}"
          ${option === value ? 'selected' : ''}
        >${web.escape(option)}</option>`
      ),
      $select = web.html`<select class="input">
        ${$options.join('')}
      </select>`,
      $icon = web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`;
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $select.addEventListener('change', async (_event) => {
      await profileDB.set([mod.id, opt.key], $select.value);
      notifications.onChange();
    });
    return web.render($label, $select, $icon);
  },

  text: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      value = await profileDB.get([mod.id, opt.key], opt.value),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
      $icon = web.html`${await components.feather('type', { class: 'input-icon' })}`;
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $input.addEventListener('change', async (_event) => {
      await profileDB.set([mod.id, opt.key], $input.value);
      notifications.onChange();
    });
    return web.render($label, $input, $icon);
  },

  number: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      value = await profileDB.get([mod.id, opt.key], opt.value),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $input = web.html`<input type="number" class="input" value="${value}">`,
      $icon = web.html`${await components.feather('hash', { class: 'input-icon' })}`;
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $input.addEventListener('change', async (_event) => {
      await profileDB.set([mod.id, opt.key], $input.value);
      notifications.onChange();
    });
    return web.render($label, $input, $icon);
  },

  color: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      value = await profileDB.get([mod.id, opt.key], opt.value),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $input = web.html`<input type="text" class="input">`,
      $icon = web.html`${await components.feather('droplet', { class: 'input-icon' })}`,
      paint = () => {
        $input.style.background = $picker.toBackground();
        const [r, g, b] = $picker
          .toRGBAString()
          .slice(5, -1)
          .split(',')
          .map((i) => parseInt(i));
        $input.style.color = fmt.rgbContrast(r, g, b);
        $input.style.padding = '';
      },
      $picker = new JSColor($input, {
        value,
        format: 'rgba',
        previewSize: 0,
        borderRadius: 3,
        borderColor: 'var(--theme--ui_divider)',
        controlBorderColor: 'var(--theme--ui_divider)',
        backgroundColor: 'var(--theme--bg)',
        onInput: paint,
        onChange: paint,
      });
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $input.addEventListener('change', async (_event) => {
      await profileDB.set([mod.id, opt.key], $input.value);
      notifications.onChange();
    });
    paint();
    return web.render($label, $input, $icon);
  },

  file: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      { filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $pseudo = web.html`<span class="input"><span class="input-placeholder">Upload file...</span></span>`,
      $input = web.html`<input type="file" class="hidden" accept=${web.escape(
        opt.extensions.join(',')
      )}>`,
      $icon = web.html`${await components.feather('file', { class: 'input-icon' })}`,
      $filename = web.html`<span>${web.escape(filename || 'none')}</span>`,
      $latest = web.render(web.html`<button class="file-latest">Latest: </button>`, $filename);
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $input.addEventListener('change', (event) => {
      const file = event.target.files[0],
        reader = new FileReader();
      reader.onload = async (progress) => {
        $filename.innerText = file.name;
        await profileDB.set([mod.id, opt.key], {
          filename: file.name,
          content: progress.currentTarget.result,
        });
        notifications.onChange();
      };
      reader.readAsText(file);
    });
    $latest.addEventListener('click', (_event) => {
      $filename.innerText = 'none';
      profileDB.set([mod.id, opt.key], {});
    });
    return web.render(
      web.html`<div></div>`,
      web.render($label, $input, $pseudo, $icon),
      $latest
    );
  },

  hotkey: async (mod, opt) => {
    const profileDB = await registry.profileDB(),
      value = await profileDB.get([mod.id, opt.key], opt.value),
      $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
      $label = web.render(
        web.html`<label class="input-label"></label>`,
        web.render(web.html`<p></p>`, opt.tooltip ? $tooltipIcon : '', opt.label)
      ),
      $input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
      $icon = web.html`${await components.feather('command', { class: 'input-icon' })}`;
    if (opt.tooltip)
      components.addTooltip($tooltipIcon, opt.tooltip, {
        offsetDirection: 'left',
        maxLines: 3,
      });
    $input.addEventListener('keydown', async (event) => {
      event.preventDefault();
      const pressed = [],
        modifiers = {
          metaKey: 'Meta',
          ctrlKey: 'Control',
          altKey: 'Alt',
          shiftKey: 'Shift',
        };
      for (const modifier in modifiers) {
        if (event[modifier]) pressed.push(modifiers[modifier]);
      }
      const empty = ['Backspace', 'Delete'].includes(event.key) && !pressed.length;
      if (!empty && !pressed.includes(event.key)) {
        let key = event.key;
        if (key === ' ') key = 'Space';
        if (key === '+') key = 'Plus';
        if (key.length === 1) key = event.key.toUpperCase();
        pressed.push(key);
      }
      $input.value = pressed.join('+');
      await profileDB.set([mod.id, opt.key], $input.value);
      notifications.onChange();
    });
    return web.render($label, $input, $icon);
  },
};
