import React from "react";
import ReactMarkdown from "react-markdown";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
import remarkGfm from "remark-gfm";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { okaidia } from "react-syntax-highlighter/dist/esm/styles/prism";
import "katex/dist/katex.min.css";
import "./MarkdownView.css";
import {useLinks} from "../../utils/queries/markdown-queries";

const Translate = ({variable, value}) => {
    if (variable.type.base_type === "markdown" || variable.type.base_type === "string" || variable.type.base_type === "enum") {
        return value;
    }
    if(variable.type.base_type === "list"){
        if (!variable.type.extend_type)
            return [];

        return (value || []).map((item, index) => Translate({
            variable: {name: index, type: variable.type.extend_type},
            value: item,
        })).map((item) => variable.type.definition.iter_layout.replaceAll('<item/>', item)).join("");
    }
    if(variable.type.base_type === "template"){
        return ParseTemplate({
            template: variable.type.definition.template,
            variables: value
        });
    }
};


const ParseTemplate = ({template, variables}) => {
    if(!template || !Array.isArray(template.parameters)) return '';
    const vars = variables || {};
    let res = template.layout ?? '';
    for (const parameter of template.parameters) {
        res = res.replaceAll(`<${parameter.name}/>`, Translate({
            variable: parameter,
            value: vars[parameter.name]
        }));
    }
    return res;
};


// Markdown content is authored by users and rendered for everyone
// (including the unauthenticated /pg/* route), so raw HTML must be
// sanitized to prevent stored XSS. className is kept on code/span/div so
// syntax highlighting and KaTeX (which runs after sanitize) still work;
// scripts, event handlers and javascript: URLs are stripped.
const sanitizeSchema = {
    ...defaultSchema,
    attributes: {
        ...defaultSchema.attributes,
        code: [...(defaultSchema.attributes?.code || []), ["className"]],
        span: [...(defaultSchema.attributes?.span || []), ["className"]],
        div: [...(defaultSchema.attributes?.div || []), ["className"]],
    },
};

const MarkdownView = ({ content, template, height="auto" }) => {
    const {data: links, isLoading} = useLinks();

    if (isLoading)
        return (<p>Loading...</p>);
    const linkDefinitions = "\n<!-- Definitions -->\n" + links.join("\n");
    const _template = template || {
        parameters: [
            {
                name: "markdown",
                type: {
                    base_type: "markdown",
                    definition: {}
                }
            }
        ],
        layout: "<markdown/>",
        title: "default"
    };

    return (
        <div className="markdown-preview" style={{height}}>
            <ReactMarkdown
                children={ParseTemplate({
                    template: _template,
                    variables: content
                }) + "\n" + linkDefinitions}
                remarkPlugins={[remarkMath, remarkGfm]}
                rehypePlugins={[rehypeRaw, [rehypeSanitize, sanitizeSchema], rehypeKatex]}
                components={{
                    code({ node, inline, className, children, ...props }) {
                        const match = /language-(\w+)/.exec(className || "");
                        return !inline && match ? (
                            <SyntaxHighlighter
                                style={okaidia}
                                language={match[1]}
                                PreTag="div"
                                {...props}
                            >
                                {String(children).replace(/\n$/, "")}
                            </SyntaxHighlighter>
                        ) : (
                            <code className={className} {...props}>
                                {children}
                            </code>
                        );
                    },
                }}
            />
        </div>
    );
};

export default MarkdownView;