var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from) {
    for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
        to[j] = from[i];
    return to;
};
import React from 'react';
import styled from '@emotion/styled';
import { createComponent } from '@workday/canvas-kit-react/common';
import { useDialogModel, Dialog } from '@workday/canvas-kit-react/dialog';
import { colors, space, type } from '@workday/canvas-kit-react/tokens';
import { MDX, MdxJSToJSX } from './MDXElements';
import { Hyperlink } from '@workday/canvas-kit-react/button';
import { docs } from './docs';
import { Value } from './Value';
/** React context to track the current rendering context to avoid tables inside tables */
export var RenderContext = React.createContext('table');
/**
 * React context to track the current heading level. This is useful to relatively change heading
 * levels of a subtree
 */
export var HeadingLevelContext = React.createContext(3);
/**
 * React context to keep track of the current indent level
 */
export var IndentLevelContext = React.createContext(0);
/**
 * Utility function for getting non-breaking space for code formatting. It will print a string of
 * non-breaking spaces according to the level provided. These characters are safe for a React render
 * function.
 */
export function indent(level) {
    return __spreadArray([], Array(level * 2)).map(function (v) { return '\u00A0'; }).join('');
}
export function capitalize(input) {
    return input.charAt(0).toUpperCase() + input.slice(1);
}
/**
 * Special heading component that uses @mdx-js/react heading components, but is also aware of
 * relative heading levels.
 */
export var Heading = createComponent('h4')({
    displayName: 'MDXHeading',
    Component: function (_a) {
        var _b = _a.headingOffset, headingOffset = _b === void 0 ? 0 : _b, elemProps = __rest(_a, ["headingOffset"]);
        var headingLevel = React.useContext(HeadingLevelContext);
        var as = "h" + (headingLevel + headingOffset); // Make Typescript happy
        return React.createElement(MDX, __assign({ as: as }, elemProps));
    },
});
export function renderTypeParameters(typeParameters) {
    return typeParameters && typeParameters.length ? (React.createElement(RenderContext.Provider, { value: "inline" },
        React.createElement("span", null, "<"),
        typeParameters.map(function (p, index) {
            return (React.createElement(React.Fragment, { key: index },
                index !== 0 && React.createElement("span", { className: "token punctuation" }, ", "),
                React.createElement(Value, { value: p })));
        }),
        React.createElement("span", null, ">"))) : ('');
}
var ButtonHyperLink = Hyperlink.as('button');
export var SymbolDialog = function (_a) {
    var value = _a.value;
    var _b = React.useState(undefined), symbol = _b[0], setSymbol = _b[1];
    var model = useDialogModel({
        onShow: function () {
            setSymbol(docs.find(function (d) { return value.name === d.name; }) || undefined);
        },
    });
    return (React.createElement(Dialog, { model: model },
        React.createElement(React.Fragment, null,
            React.createElement(Dialog.Target, { as: ButtonHyperLink, className: "token symbol", style: {
                    border: 'none',
                    background: 'transparent',
                    fontSize: 'inherit',
                    fontFamily: 'inherit',
                }, "aria-haspopup": "true" }, value.displayName || value.name),
            renderTypeParameters(value.typeParameters)),
        React.createElement(Dialog.Popper, null,
            React.createElement(Dialog.Card, { maxHeight: "50vh", maxWidth: "90vh" },
                React.createElement(Dialog.CloseIcon, null),
                React.createElement(Dialog.Heading, null, value.name),
                React.createElement(Dialog.Body, null,
                    React.createElement(RenderContext.Provider, { value: "table" },
                        React.createElement(IndentLevelContext.Provider, { value: 0 }, symbol ? (React.createElement(SymbolDoc, { name: value.name, headingStart: 3, hideHeading: true })) : (React.createElement(React.Fragment, null,
                            React.createElement("p", null, "Basic type information:"),
                            React.createElement("pre", null,
                                React.createElement("code", null, value.value)))))))))));
};
function createColor(color) {
    return {
        color: colors[color],
    };
}
var StyledSymbolDoc = styled('div')({
    marginBottom: space.m,
    'button[data-symbol]': {
        border: 'none',
        background: 'transparent',
        fontSize: 'inherit',
        fontFamily: 'inherit',
    },
    code: {
        fontSize: type.properties.fontSizes[14],
        lineHeight: 1.5,
        fontFamily: type.properties.fontFamilies.monospace,
        whiteSpace: 'nowrap',
        '.token': {
            '&.string': createColor('juicyPear600'),
            '&.symbol': createColor('grapeSoda600'),
            '&.property': createColor('berrySmoothie600'),
            '&.primitive': createColor('pomegranate600'),
            '&.number': createColor('pomegranate600'),
            '&.boolean': createColor('pomegranate600'),
            '&.variable': createColor('pomegranate600'),
            '&.keyword': createColor('pomegranate600'),
            '&.punctuation': createColor('blackPepper600'),
            '&.operator': createColor('blackPepper600'),
            '&.bold': { fontWeight: 700 },
        },
    },
});
function getSymbolDocChildren(doc, meta) {
    if (!doc) {
        return React.createElement("div", null, "Not Found");
    }
    if (doc && doc.type) {
        return React.createElement(Value, { value: doc.type, doc: doc, meta: meta });
    }
    return React.createElement("div", null, "Not Found");
}
function findDoc(_a) {
    var name = _a.name, fileName = _a.fileName;
    var doc = (docs || []).find(function (d) {
        return d.name === name && (fileName ? d.fileName.includes(fileName) : true);
    });
    if ((doc === null || doc === void 0 ? void 0 : doc.type.kind) === 'alias') {
        return findDoc({ name: doc.type.name });
    }
    return doc;
}
export var useDoc = function (criteria) {
    var doc = React.useState(function () {
        return findDoc(criteria);
    })[0];
    return doc;
};
/**
 * Renders the `<Value>` of a exported symbol without any wrapper. This should be used when nesting
 * inside a `<SymbolDoc>` component.
 */
export var SymbolValue = function (props) {
    var doc = useDoc(props);
    return getSymbolDocChildren(doc);
};
/**
 * Renders just the description of an exported symbol.
 */
export var SymbolDescription = function (props) {
    var doc = useDoc(props);
    return doc ? React.createElement(MdxJSToJSX, null, doc.description) : null;
};
/**
 * Renders an exported symbol as a doc object. This will render JSDoc tags, description and setup
 * rendering contexts for headers.
 */
export var SymbolDoc = function (_a) {
    var name = _a.name, fileName = _a.fileName, _b = _a.headingStart, headingStart = _b === void 0 ? 3 : _b, _c = _a.hideDescription, hideDescription = _c === void 0 ? false : _c, _d = _a.hideHeading, hideHeading = _d === void 0 ? false : _d, descriptionOverride = _a.descriptionOverride, meta = _a.meta, elemProps = __rest(_a, ["name", "fileName", "headingStart", "hideDescription", "hideHeading", "descriptionOverride", "meta"]);
    var doc = useDoc({ name: name, fileName: fileName });
    var children = getSymbolDocChildren(doc, meta);
    var requiresCodeWrapper = [
        'symbol',
        'generic',
        'array',
        'indexedAccess',
        'qualifiedName',
        'parenthesis',
        'typeParameter',
        'keyof',
        'type',
        'conditional',
        'indexSignature',
        'tuple',
        'external',
        'number',
        'string',
        'boolean',
        'primitive',
        'unknown',
        'union',
        'intersection',
        'function',
        'callExpression',
    ].includes((doc === null || doc === void 0 ? void 0 : doc.type.kind) || 'notFound');
    var contents = requiresCodeWrapper ? (React.createElement("code", { style: { display: 'block' } }, children)) : (children);
    return (React.createElement(StyledSymbolDoc, __assign({}, elemProps),
        React.createElement(HeadingLevelContext.Provider, { value: headingStart },
            !hideHeading && React.createElement(Heading, null, name),
            !hideDescription && doc && (React.createElement(MdxJSToJSX, null, descriptionOverride || doc.description)),
            contents)));
};
