import { Marked, type RendererObject } from "marked";
import { decode } from "tiny-decode";
import { parsePartialHTMLTag } from "./parse_partial_html_tag";

const renderer: RendererObject = {
  code({ text }) {
    return `\n[code]${text}[/code]\n`;
  },
  blockquote({ tokens }) {
    return `\n[quote]${this.parser.parseInline(tokens)}[/quote]\n`;
  },
  html(token) {
    const { type, raw } = token;
    if (type === "html") {
      const tag = parsePartialHTMLTag(raw);
      switch (tag.tag) {
        case "a":
          if (tag.type === "open") {
            if (tag.attributes?.href) {
              return `[url=${tag.attributes.href}]`;
            }
          } else if (tag.type === "close") {
            return "[/url]";
          }
          console.error("ERROR: unhandled anchor in markdownToBbcode.html", token, tag);
          throw new Error("Unhandled anchor HTML token in BBCode renderer");
      }
    }
    console.error("ERROR: unhandled token in markdownToBbcode.html", token);
    throw new Error("Unknown HTML token not supported by BBCode renderer");
  },
  heading({ tokens }) {
    return `\n${this.parser.parseInline(tokens)}\n`;
  },
  hr() {
    return `\n===\n`;
  },
  list({ ordered, items }) {
    const tag = ordered ? "ol" : "ul";
    return `\n[${tag}]\n${items.map(this.listitem).join("\n")}[/${tag}]\n`;
  },
  listitem({ tokens }) {
    return `[li]${this.parser.parseInline(tokens)}[/li]\n`;
  },
  checkbox(token) {
    console.error("ERROR: unhandled token in markdownToBbcode.checkbox", token);
    throw new Error("Not supported by BBCode: checkbox");
  },
  paragraph({ tokens }) {
    return `\n${this.parser.parseInline(tokens)}\n`;
  },
  table({ header, rows }) {
    return `\n[table]\n${this.tablerow({ text: header.map(this.tablecell).join("\n") })}\n${rows
      .map((row) => this.tablerow({ text: row.map(this.tablecell).join("\n") }))
      .join("\n")}[/table]\n`;
  },
  tablerow({ text }) {
    return `[tr]\n${text}[/tr]\n`;
  },
  tablecell({ header, tokens }) {
    const tag = header ? "th" : "td";
    return `[${tag}]${this.parser.parseInline(tokens)}[/${tag}]\n`;
  },
  strong({ tokens }) {
    return `[b]${this.parser.parseInline(tokens)}[/b]`;
  },
  em({ tokens }) {
    return `[i]${this.parser.parseInline(tokens)}[/i]`;
  },
  codespan({ text }) {
    return text;
  },
  br() {
    return "\n\n";
  },
  del({ tokens }) {
    return `[s]${this.parser.parseInline(tokens)}[/s]`;
  },
  link({ href, tokens }) {
    return `[url=${href}]${this.parser.parseInline(tokens)}[/url]`;
  },
  image({ href }) {
    return `[img]${href}[/img]`;
  },
};

const bbcodeRenderer = new Marked({ renderer, async: false });

export const markdownToBbcode = (text: string) => decode(bbcodeRenderer.parse(text, { async: false }).trim());
