import * as React from "react";
import styled from "styled-components";
import { Primitive } from "utility-types";
import { IntegrationService, IntegrationType } from "../../types";
import type { IntegrationSettings } from "../../types";
import { urlRegex } from "../../utils/urls";
import Image from "../components/Img";
import Berrycast from "./Berrycast";
import Diagrams from "./Diagrams";
import Gist from "./Gist";
import GitLabSnippet from "./GitLabSnippet";
import InVision from "./InVision";
import JSFiddle from "./JSFiddle";
import Linkedin from "./Linkedin";
import Spotify from "./Spotify";
import Trello from "./Trello";
import Vimeo from "./Vimeo";
import YouTube from "./YouTube";

export type EmbedProps = {
  isSelected: boolean;
  isEditable: boolean;
  embed: EmbedDescriptor;
  matches: RegExpMatchArray;
  attrs: {
    href: string;
  };
};

const Img = styled(Image)`
  border-radius: 2px;
  background: #fff;
  box-shadow: 0 0 0 1px #fff;
  margin: 3px;
  width: 18px;
  height: 18px;
`;

export class EmbedDescriptor {
  /** An icon that will be used to represent the embed in menus */
  icon?: React.ReactNode;
  /** The name of the embed. If this embed has a matching integration it should match IntegrationService */
  name?: string;
  /** The title of the embed */
  title: string;
  /** A keyboard shortcut that will trigger the embed */
  shortcut?: string;
  /** Keywords that will match this embed in menus */
  keywords?: string;
  /** A tooltip that will be shown in menus */
  tooltip?: string;
  /** Whether the embed should be hidden in menus by default */
  defaultHidden?: boolean;
  /** A regex that will be used to match the embed when pasting a URL */
  regexMatch?: RegExp[];
  /**
   * A function that will be used to transform the URL. The resulting string is passed as the src
   * to the iframe. You can perform any transformations you want here, including changing the domain
   *
   * If a custom display is needed this function should be left undefined and `component` should be
   * used instead.
   */
  transformMatch?: (matches: RegExpMatchArray) => string;
  /** The node attributes */
  attrs?: Record<string, Primitive>;
  /** Whether the embed should be visible in menus, always true */
  visible?: boolean;
  /**
   * A React component that will be used to render the embed, if displaying a simple iframe then
   * `transformMatch` should be used instead.
   */
  component?: React.FunctionComponent<EmbedProps>;
  /** The integration settings, if any */
  settings?: IntegrationSettings<IntegrationType.Embed>;

  constructor(options: Omit<EmbedDescriptor, "matcher">) {
    this.icon = options.icon;
    this.name = options.name;
    this.title = options.title;
    this.shortcut = options.shortcut;
    this.keywords = options.keywords;
    this.tooltip = options.tooltip;
    this.defaultHidden = options.defaultHidden;
    this.regexMatch = options.regexMatch;
    this.transformMatch = options.transformMatch;
    this.attrs = options.attrs;
    this.visible = options.visible;
    this.component = options.component;
  }

  matcher(url: string): false | RegExpMatchArray {
    const regexes = this.regexMatch ?? [];
    const settingsDomainRegex = urlRegex(this.settings?.url);

    if (settingsDomainRegex) {
      regexes.unshift(settingsDomainRegex);
    }

    for (const regex of regexes) {
      const result = url.match(regex);
      if (result) {
        return result;
      }
    }

    return false;
  }
}

const embeds: EmbedDescriptor[] = [
  new EmbedDescriptor({
    title: "Abstract",
    keywords: "design",
    defaultHidden: true,
    icon: <Img src="/images/abstract.png" alt="Abstract" />,
    regexMatch: [
      new RegExp("^https?://share\\.(?:go)?abstract\\.com/(.*)$"),
      new RegExp("^https?://app\\.(?:go)?abstract\\.com/(?:share|embed)/(.*)$"),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://app.goabstract.com/embed/${matches[1]}`,
  }),
  new EmbedDescriptor({
    title: "Airtable",
    keywords: "spreadsheet",
    icon: <Img src="/images/airtable.png" alt="Airtable" />,
    regexMatch: [
      new RegExp("^https://airtable.com/(?:embed/)?(app.*/)?(shr.*)$"),
      new RegExp("^https://airtable.com/(app.*/)?(pag.*)/form$"),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://airtable.com/embed/${matches[1] ?? ""}${matches[2]}`,
  }),
  new EmbedDescriptor({
    title: "Berrycast",
    keywords: "video",
    defaultHidden: true,
    regexMatch: [/^https:\/\/(www\.)?berrycast.com\/conversations\/(.*)$/i],
    icon: <Img src="/images/berrycast.png" alt="Berrycast" />,
    component: Berrycast,
  }),
  new EmbedDescriptor({
    title: "Bilibili",
    keywords: "video",
    defaultHidden: true,
    regexMatch: [
      /(?:https?:\/\/)?(www\.bilibili\.com)\/video\/([\w\d]+)?(\?\S+)?/i,
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://player.bilibili.com/player.html?bvid=${matches[2]}&page=1&high_quality=1`,
    icon: <Img src="/images/bilibili.png" alt="Bilibili" />,
  }),
  new EmbedDescriptor({
    title: "Camunda Modeler",
    keywords: "bpmn process cawemo",
    defaultHidden: true,
    regexMatch: [
      new RegExp("^https?://modeler.cloud.camunda.io/(?:share|embed)/(.*)$"),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://modeler.cloud.camunda.io/embed/${matches[1]}`,
    icon: <Img src="/images/camunda.png" alt="Camunda" />,
  }),
  new EmbedDescriptor({
    title: "Canva",
    keywords: "design",
    regexMatch: [
      /^https:\/\/(?:www\.)?canva\.com\/design\/([a-zA-Z0-9]*)\/(.*)$/,
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://www.canva.com/design/${matches[1]}/view?embed`,
    icon: <Img src="/images/canva.png" alt="Canva" />,
  }),
  new EmbedDescriptor({
    title: "Cawemo",
    keywords: "bpmn process",
    defaultHidden: true,
    regexMatch: [new RegExp("^https?://cawemo.com/(?:share|embed)/(.*)$")],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://cawemo.com/embed/${matches[1]}`,
    icon: <Img src="/images/cawemo.png" alt="Cawemo" />,
  }),
  new EmbedDescriptor({
    title: "ClickUp",
    keywords: "project",
    regexMatch: [
      new RegExp("^https?://share\\.clickup\\.com/[a-z]/[a-z]/(.*)/(.*)$"),
      new RegExp(
        "^https?://sharing\\.clickup\\.com/[0-9]+/[a-z]/[a-z]/(.*)/(.*)$"
      ),
    ],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/clickup.png" alt="ClickUp" />,
  }),
  new EmbedDescriptor({
    title: "Codepen",
    keywords: "code editor",
    regexMatch: [new RegExp("^https://codepen.io/(.*?)/(pen|embed)/(.*)$")],
    transformMatch: (matches) =>
      `https://codepen.io/${matches[1]}/embed/${matches[3]}`,
    icon: <Img src="/images/codepen.png" alt="Codepen" />,
  }),
  new EmbedDescriptor({
    title: "DBDiagram",
    keywords: "diagrams database",
    regexMatch: [new RegExp("^https://dbdiagram.io/(embed|d)/(\\w+)$")],
    transformMatch: (matches) => `https://dbdiagram.io/embed/${matches[2]}`,
    icon: <Img src="/images/dbdiagram.png" alt="DBDiagram" />,
  }),
  new EmbedDescriptor({
    title: "Diagrams.net",
    name: IntegrationService.Diagrams,
    keywords: "diagrams drawio",
    regexMatch: [/^https:\/\/viewer\.diagrams\.net\/(?!proxy).*(title=\\w+)?/],
    icon: <Img src="/images/diagrams.png" alt="Diagrams.net" />,
    component: Diagrams,
  }),
  new EmbedDescriptor({
    title: "Descript",
    keywords: "audio",
    regexMatch: [new RegExp("^https?://share\\.descript\\.com/view/(\\w+)$")],
    transformMatch: (matches) =>
      `https://share.descript.com/embed/${matches[1]}`,
    icon: <Img src="/images/descript.png" alt="Descript" />,
  }),
  new EmbedDescriptor({
    title: "Figma",
    keywords: "design svg vector",
    regexMatch: [
      new RegExp(
        "^https://([w.-]+\\.)?figma\\.com/(file|proto)/([0-9a-zA-Z]{22,128})(?:/.*)?$"
      ),
    ],
    transformMatch: (matches) =>
      `https://www.figma.com/embed?embed_host=outline&url=${encodeURIComponent(
        matches[0]
      )}`,
    icon: <Img src="/images/figma.png" alt="Figma" />,
  }),
  new EmbedDescriptor({
    title: "Framer",
    keywords: "design prototyping",
    regexMatch: [new RegExp("^https://framer.cloud/(.*)$")],
    transformMatch: (matches) => matches[0],
    icon: <Img src="/images/framer.png" alt="Framer" />,
  }),
  new EmbedDescriptor({
    title: "GitHub Gist",
    keywords: "code",
    regexMatch: [
      new RegExp(
        "^https://gist\\.github\\.com/([a-zA-Z\\d](?:[a-zA-Z\\d]|-(?=[a-zA-Z\\d])){0,38})/(.*)$"
      ),
    ],
    icon: <Img src="/images/github-gist.png" alt="GitHub" />,
    component: Gist,
  }),
  new EmbedDescriptor({
    title: "GitLab Snippet",
    keywords: "code",
    regexMatch: [
      new RegExp(`^https://gitlab\\.com/(([a-zA-Z\\d-]+)/)*-/snippets/\\d+$`),
    ],
    icon: <Img src="/images/gitlab.png" alt="GitLab" />,
    component: GitLabSnippet,
  }),
  new EmbedDescriptor({
    title: "Gliffy",
    keywords: "diagram",
    regexMatch: [new RegExp("https?://go\\.gliffy\\.com/go/share/(.*)$")],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/gliffy.png" alt="Gliffy" />,
  }),
  new EmbedDescriptor({
    title: "Google Maps",
    keywords: "maps",
    regexMatch: [new RegExp("^https?://www\\.google\\.com/maps/embed\\?(.*)$")],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/google-maps.png" alt="Google Maps" />,
    visible: true,
  }),
  new EmbedDescriptor({
    title: "Google Drawings",
    keywords: "drawings",
    transformMatch: (matches: RegExpMatchArray) =>
      matches[0].replace("/edit", "/preview"),
    regexMatch: [
      new RegExp(
        "^https://docs\\.google\\.com/drawings/d/(.*)/(edit|preview)(.*)$"
      ),
    ],
    icon: <Img src="/images/google-drawings.png" alt="Google Drawings" />,
  }),
  new EmbedDescriptor({
    title: "Google Drive",
    keywords: "drive",
    regexMatch: [new RegExp("^https?://drive\\.google\\.com/file/d/(.*)$")],
    transformMatch: (matches) =>
      matches[0].replace("/view", "/preview").replace("/edit", "/preview"),
    icon: <Img src="/images/google-drive.png" alt="Google Drive" />,
  }),
  new EmbedDescriptor({
    title: "Google Docs",
    keywords: "documents word",
    regexMatch: [new RegExp("^https?://docs\\.google\\.com/document/(.*)$")],
    transformMatch: (matches) =>
      matches[0].replace("/view", "/preview").replace("/edit", "/preview"),
    icon: <Img src="/images/google-docs.png" alt="Google Docs" />,
  }),
  new EmbedDescriptor({
    title: "Google Sheets",
    keywords: "excel spreadsheet",
    regexMatch: [
      new RegExp("^https?://docs\\.google\\.com/spreadsheets/d/(.*)$"),
    ],
    transformMatch: (matches) =>
      matches[0].replace("/view", "/preview").replace("/edit", "/preview"),
    icon: <Img src="/images/google-sheets.png" alt="Google Sheets" />,
  }),
  new EmbedDescriptor({
    title: "Google Slides",
    keywords: "presentation slideshow",
    regexMatch: [
      new RegExp("^https?://docs\\.google\\.com/presentation/d/(.*)$"),
    ],
    transformMatch: (matches) =>
      matches[0].replace("/edit", "/preview").replace("/pub", "/embed"),
    icon: <Img src="/images/google-slides.png" alt="Google Slides" />,
  }),
  new EmbedDescriptor({
    title: "Google Calendar",
    keywords: "calendar",
    regexMatch: [
      new RegExp(
        "^https?://calendar\\.google\\.com/calendar/embed\\?src=(.*)$"
      ),
    ],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/google-calendar.png" alt="Google Calendar" />,
  }),
  new EmbedDescriptor({
    title: "Google Forms",
    keywords: "form survey",
    regexMatch: [new RegExp("^https?://docs\\.google\\.com/forms/d/(.+)$")],
    transformMatch: (matches: RegExpMatchArray) =>
      matches[0].replace(
        /\/(edit|viewform)(\?.+)?$/,
        "/viewform?embedded=true"
      ),
    icon: <Img src="/images/google-forms.png" alt="Google Forms" />,
  }),
  new EmbedDescriptor({
    title: "Google Looker Studio",
    keywords: "bi business intelligence",
    regexMatch: [
      new RegExp(
        "^https?://(lookerstudio|datastudio)\\.google\\.com/(embed|u/0)/reporting/(.*)/page/(.*)(/edit)?$"
      ),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      matches[0].replace("u/0", "embed").replace("/edit", ""),
    icon: (
      <Img src="/images/google-lookerstudio.png" alt="Google Looker Studio" />
    ),
  }),
  new EmbedDescriptor({
    title: "Grist",
    name: IntegrationService.Grist,
    keywords: "spreadsheet",
    regexMatch: [new RegExp("^https?://([a-z.-]+\\.)?getgrist\\.com/(.+)$")],
    transformMatch: (matches: RegExpMatchArray) => {
      if (matches[0].includes("style=singlePage")) {
        return matches[0];
      }

      return matches[0].replace(/(\?embed=true)?$/, "?embed=true");
    },
    icon: <Img src="/images/grist.png" alt="Grist" />,
  }),
  new EmbedDescriptor({
    title: "Instagram",
    keywords: "post",
    regexMatch: [
      /^https?:\/\/www\.instagram\.com\/(p|reel)\/([\w-]+)(\/?utm_source=\w+)?/,
    ],
    transformMatch: (matches: RegExpMatchArray) => `${matches[0]}/embed`,
    icon: <Img src="/images/instagram.png" alt="Instagram" />,
  }),
  new EmbedDescriptor({
    title: "InVision",
    keywords: "design prototype",
    defaultHidden: true,
    regexMatch: [
      /^https:\/\/(invis\.io\/.*)|(projects\.invisionapp\.com\/share\/.*)$/,
      /^https:\/\/(opal\.invisionapp\.com\/static-signed\/live-embed\/.*)$/,
    ],
    icon: <Img src="/images/invision.png" alt="InVision" />,
    component: InVision,
  }),
  new EmbedDescriptor({
    title: "JSFiddle",
    keywords: "code",
    defaultHidden: true,
    regexMatch: [new RegExp("^https?://jsfiddle\\.net/(.*)/(.*)$")],
    icon: <Img src="/images/jsfiddle.png" alt="JSFiddle" />,
    component: JSFiddle,
  }),
  new EmbedDescriptor({
    title: "LinkedIn",
    keywords: "post",
    defaultHidden: true,
    regexMatch: [
      /^https:\/\/www\.linkedin\.com\/(?:posts\/.*-(ugcPost|activity)-(\d+)-.*|(embed)\/(?:feed\/update\/urn:li:(?:ugcPost|share):(?:\d+)))/,
    ],
    icon: <Img src="/images/linkedin.png" alt="LinkedIn" />,
    component: Linkedin,
  }),
  new EmbedDescriptor({
    title: "Loom",
    keywords: "video screencast",
    regexMatch: [/^https:\/\/(www\.)?(use)?loom\.com\/(embed|share)\/(.*)$/],
    transformMatch: (matches: RegExpMatchArray) =>
      matches[0].replace("share", "embed"),
    icon: <Img src="/images/loom.png" alt="Loom" />,
  }),
  new EmbedDescriptor({
    title: "Lucidchart",
    keywords: "chart",
    regexMatch: [
      /^https?:\/\/(www\.|app\.)?(lucidchart\.com|lucid\.app)\/documents\/(embeddedchart|view|edit)\/(?<chartId>[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})(?:.*)?$/,
      /^https?:\/\/(www\.|app\.)?(lucid\.app|lucidchart\.com)\/lucidchart\/(?<chartId>[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\/(embeddedchart|view|edit)(?:.*)?$/,
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://lucidchart.com/documents/embeddedchart/${matches.groups?.chartId}`,
    icon: <Img src="/images/lucidchart.png" alt="Lucidchart" />,
  }),
  new EmbedDescriptor({
    title: "Marvel",
    keywords: "design prototype",
    regexMatch: [new RegExp("^https://marvelapp\\.com/([A-Za-z0-9-]{6})/?$")],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/marvel.png" alt="Marvel" />,
  }),
  new EmbedDescriptor({
    title: "Mindmeister",
    keywords: "mindmap",
    regexMatch: [
      new RegExp(
        "^https://([w.-]+\\.)?(mindmeister\\.com|mm\\.tt)(/maps/public_map_shell)?/(\\d+)(\\?t=.*)?(/.*)?$"
      ),
    ],
    transformMatch: (matches: RegExpMatchArray) => {
      const chartId = matches[4] + (matches[5] || "") + (matches[6] || "");
      return `https://www.mindmeister.com/maps/public_map_shell/${chartId}`;
    },
    icon: <Img src="/images/mindmeister.png" alt="Mindmeister" />,
  }),
  new EmbedDescriptor({
    title: "Miro",
    keywords: "whiteboard",
    regexMatch: [/^https:\/\/(realtimeboard|miro)\.com\/app\/board\/(.*)$/],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://${matches[1]}.com/app/embed/${matches[2]}`,
    icon: <Img src="/images/miro.png" alt="Miro" />,
  }),
  new EmbedDescriptor({
    title: "Mode",
    keywords: "analytics",
    defaultHidden: true,
    regexMatch: [
      new RegExp("^https://([w.-]+\\.)?modeanalytics\\.com/(.*)/reports/(.*)$"),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `${matches[0].replace(/\/embed$/, "")}/embed`,
    icon: <Img src="/images/mode-analytics.png" alt="Mode" />,
  }),
  new EmbedDescriptor({
    title: "Otter.ai",
    keywords: "audio transcription meeting notes",
    defaultHidden: true,
    regexMatch: [new RegExp("^https?://otter\\.ai/[su]/(.*)$")],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/otter.png" alt="Otter.ai" />,
  }),
  new EmbedDescriptor({
    title: "Pitch",
    keywords: "presentation",
    defaultHidden: true,
    regexMatch: [
      new RegExp(
        "^https?://app\\.pitch\\.com/app/(?:presentation/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|public/player)/(.*)$"
      ),
      new RegExp("^https?://pitch\\.com/embed/(.*)$"),
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://pitch.com/embed/${matches[1]}`,
    icon: <Img src="/images/pitch.png" alt="Pitch" />,
  }),
  new EmbedDescriptor({
    title: "Prezi",
    keywords: "presentation",
    regexMatch: [new RegExp("^https://prezi\\.com/view/(.*)$")],
    transformMatch: (matches: RegExpMatchArray) =>
      `${matches[0].replace(/\/embed$/, "")}/embed`,
    icon: <Img src="/images/prezi.png" alt="Prezi" />,
  }),
  new EmbedDescriptor({
    title: "Scribe",
    keywords: "screencast",
    regexMatch: [/^https?:\/\/scribehow\.com\/shared\/(.*)$/],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://scribehow.com/embed/${matches[1]}`,
    icon: <Img src="/images/scribe.png" alt="Scribe" />,
  }),
  new EmbedDescriptor({
    title: "Spotify",
    keywords: "music",
    regexMatch: [new RegExp("^https?://open\\.spotify\\.com/(.*)$")],
    icon: <Img src="/images/spotify.png" alt="Spotify" />,
    component: Spotify,
  }),
  new EmbedDescriptor({
    title: "Tldraw",
    keywords: "draw schematics diagrams",
    regexMatch: [
      new RegExp("^https?://(beta|www|old)\\.tldraw\\.com/[rsv]/(.*)"),
    ],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/tldraw.png" alt="Tldraw" />,
  }),
  new EmbedDescriptor({
    title: "Trello",
    keywords: "kanban",
    regexMatch: [/^https:\/\/trello\.com\/(c|b)\/([^/]*)(.*)?$/],
    icon: <Img src="/images/trello.png" alt="Trello" />,
    component: Trello,
  }),
  new EmbedDescriptor({
    title: "Typeform",
    keywords: "form survey",
    regexMatch: [
      new RegExp(
        "^https://([A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)\\.typeform\\.com/to/(.*)$"
      ),
    ],
    transformMatch: (matches: RegExpMatchArray) => matches[0],
    icon: <Img src="/images/typeform.png" alt="Typeform" />,
  }),
  new EmbedDescriptor({
    title: "Valtown",
    keywords: "code",
    regexMatch: [/^https?:\/\/(?:www.)?val\.town\/(?:v|embed)\/(.*)$/],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://www.val.town/embed/${matches[1]}`,
    icon: <Img src="/images/valtown.png" alt="Valtown" />,
  }),
  new EmbedDescriptor({
    title: "Vimeo",
    keywords: "video",
    regexMatch: [
      /(http|https)?:\/\/(www\.)?vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^/]*)\/videos\/|)(\d+)(?:\/|\?)?([\d\w]+)?/,
    ],
    icon: <Img src="/images/vimeo.png" alt="Vimeo" />,
    component: Vimeo,
  }),
  new EmbedDescriptor({
    title: "Whimsical",
    keywords: "whiteboard",
    regexMatch: [
      /^https?:\/\/whimsical\.com\/[0-9a-zA-Z-_~]*-([a-zA-Z0-9]+)\/?$/,
    ],
    transformMatch: (matches: RegExpMatchArray) =>
      `https://whimsical.com/embed/${matches[1]}`,
    icon: <Img src="/images/whimsical.png" alt="Whimsical" />,
  }),
  new EmbedDescriptor({
    title: "YouTube",
    keywords: "google video",
    regexMatch: [
      /(?:https?:\/\/)?(?:www\.)?youtu\.?be(?:\.com)?\/?.*(?:watch|embed)?(?:.*v=|v\/|\/)([a-zA-Z0-9_-]{11})([\&\?](.*))?$/i,
    ],
    icon: <Img src="/images/youtube.png" alt="YouTube" />,
    component: YouTube,
  }),
];

export default embeds;
