import { LitElement, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import MarkdownIt, { type StateCore, type Token } from 'markdown-it';

function nostrPlugin(md: MarkdownIt): void {
  const npubRegex = /(npub[0-9a-zA-Z]{59})/g;

  md.core.ruler.after('inline', 'nostr_npub', (state: StateCore): boolean => {
    for (const token of state.tokens) {
      if (token.type === 'inline' && token.children) {
        for (let i = 0; i < token.children.length; i++) {
          const child = token.children[i];

          if (child.type === 'text') {
            const matches = child.content.match(npubRegex);
            if (!matches) continue;

            const newTokens: Token[] = [];
            let lastIndex = 0;

            child.content.replace(
              npubRegex,
              // @ts-ignore this is an issue with the types
              (match: string, npub: string, offset: number) => {
                if (offset > lastIndex) {
                  const textToken = new state.Token('text', '', 0);
                  textToken.content = child.content.slice(lastIndex, offset);
                  newTokens.push(textToken);
                }

                const linkOpen = new state.Token('link_open', 'a', 1);
                linkOpen.attrs = [['href', `nostr:${npub}`]];

                const text = new state.Token('text', '', 0);
                text.content = npub;

                const linkClose = new state.Token('link_close', 'a', -1);

                newTokens.push(linkOpen, text, linkClose);
                lastIndex = offset + match.length;
              },
            );

            if (lastIndex < child.content.length) {
              const textToken = new state.Token('text', '', 0);
              textToken.content = child.content.slice(lastIndex);
              newTokens.push(textToken);
            }

            token.children.splice(i, 1, ...newTokens);
            i += newTokens.length - 1;
          }
        }
      }
    }

    return true;
  });
}

@customElement('arx-markdown-content')
export class MarkdownContent extends LitElement {
  private md = new MarkdownIt({
    html: false,
    linkify: true,
    typographer: true,
    breaks: true,
  });

  @property({ type: String })
  content = '';

  static override styles = [
    css`
      :host {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
        align-items: flex-start;
        white-space: pre-wrap;
        word-wrap: break-word;
        overflow-wrap: break-word;
        text-wrap: normal;
      }

      * {
        white-space: pre-wrap;
        word-wrap: break-word;
        overflow-wrap: break-word;
        text-wrap: normal;
      }

      .text-content {
        display: contents;
      }

      h1,
      h2,
      h3,
      h4,
      h5,
      h6,
      code,
      ul,
      ol,
      blockquote {
        width: 100%;
        margin: 0;
        display: block;
      }
    `,
  ];

  constructor() {
    super();
    this.md.use(nostrPlugin);
  }

  override render() {
    return unsafeHTML(this.md.render(this.content));
  }
}
