"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertDeclareXmlContentToTs = convertDeclareXmlContentToTs;
exports.convertDeclareXmlFileToTs = convertDeclareXmlFileToTs;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
function decodeXml(value) {
    return `${value ?? ''}`
        .replace(/&quot;/g, '"')
        .replace(/&apos;/g, "'")
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&amp;/g, '&');
}
function parseAttributes(raw) {
    const attrs = {};
    const attrRegex = /([A-Za-z_][\w:-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
    let match;
    while ((match = attrRegex.exec(raw))) {
        attrs[match[1]] = decodeXml(match[2] ?? match[3] ?? '');
    }
    return attrs;
}
function parseXml(xml) {
    const root = { tag: '__root__', attrs: {}, children: [] };
    const stack = [root];
    const tagRegex = /<[^>]+>/g;
    let match;
    while ((match = tagRegex.exec(xml))) {
        const token = match[0].trim();
        if (token.startsWith('<?') || token.startsWith('<!')) {
            continue;
        }
        if (token.startsWith('</')) {
            stack.pop();
            continue;
        }
        const selfClosing = token.endsWith('/>');
        const rawContent = token.slice(1, selfClosing ? -2 : -1).trim();
        const firstSpace = rawContent.search(/\s/);
        const tag = firstSpace === -1 ? rawContent : rawContent.slice(0, firstSpace);
        const rawAttrs = firstSpace === -1 ? '' : rawContent.slice(firstSpace + 1);
        const node = {
            tag,
            attrs: parseAttributes(rawAttrs),
            children: [],
        };
        const parent = stack[stack.length - 1];
        parent.children.push(node);
        if (!selfClosing) {
            stack.push(node);
        }
    }
    const declareNode = root.children.find((child) => child.tag === 'declare');
    if (!declareNode) {
        throw new Error('Declare XML 格式不正确');
    }
    return declareNode;
}
function mapXmlTypeToTs(dataType) {
    const normalized = (dataType || '').toLowerCase();
    if (normalized === 'float' || normalized === 'number' || normalized === 'int' || normalized === 'integer') {
        return 'number';
    }
    if (normalized === 'boolean') {
        return 'boolean';
    }
    if (normalized === 'date' || normalized === 'datetime') {
        return 'Date';
    }
    return 'string';
}
function toIdentifier(value) {
    const cleaned = value.replace(/[^a-zA-Z0-9_$]/g, '_').replace(/^[^a-zA-Z_$]+/, '');
    return cleaned || 'ServiceDeclare';
}
function toDeclareNamespaceName(serviceName) {
    const normalized = toIdentifier(serviceName || 'Service');
    return normalized.endsWith('Declare') ? normalized : `${normalized}Declare`;
}
function indent(level) {
    return '  '.repeat(level);
}
function buildDescription(description, level) {
    const text = (description || '').trim();
    if (!text) {
        return [];
    }
    return [`${indent(level)}/** ${text} */`];
}
function formatObjectType(children, level) {
    if (!children.length) {
        return { text: '{}', usesFile: false };
    }
    const lines = ['{'];
    let usesFile = false;
    for (const child of children) {
        const name = (child.attrs.name || '').trim();
        if (!name) {
            continue;
        }
        const required = (child.attrs.required || '').toLowerCase() === 'true';
        const description = child.attrs.description || '';
        const converted = convertNodeToTs(child, level + 1);
        usesFile = usesFile || converted.usesFile;
        lines.push(...buildDescription(description, level + 1));
        lines.push(`${indent(level + 1)}${name}${required ? '' : '?'}: ${converted.text};`);
    }
    lines.push(`${indent(level)}}`);
    return {
        text: lines.join('\n'),
        usesFile,
    };
}
function convertNodeToTs(node, level) {
    if (node.tag === 'simple') {
        return { text: mapXmlTypeToTs(node.attrs.dataType), usesFile: false };
    }
    if (node.tag === 'file') {
        return { text: 'File', usesFile: true };
    }
    if (node.tag === 'model') {
        return { text: node.attrs.model || 'any', usesFile: false };
    }
    if (node.tag === 'array') {
        const child = node.children[0];
        if (!child) {
            return { text: 'Array<any>', usesFile: false };
        }
        const converted = convertNodeToTs(child, level);
        return {
            text: `Array<${converted.text}>`,
            usesFile: converted.usesFile,
        };
    }
    if (node.tag === 'complex') {
        return formatObjectType(node.children, level);
    }
    if (node.tag === 'multipart') {
        return formatObjectType(node.children, level);
    }
    return { text: 'any', usesFile: false };
}
function buildParametersType(parametersNode) {
    if (!parametersNode || !parametersNode.children.length) {
        return { text: '{}', usesFile: false, description: '' };
    }
    const first = parametersNode.children[0];
    if (first.tag === 'multipart') {
        const converted = formatObjectType(first.children, 2);
        return { ...converted, description: first.attrs.description || '' };
    }
    if (first.tag === 'complex') {
        const converted = formatObjectType(first.children, 2);
        return { ...converted, description: first.attrs.description || '' };
    }
    const converted = convertNodeToTs(first, 2);
    return { ...converted, description: first.attrs.description || '' };
}
function buildResultType(resultNode) {
    if (!resultNode || !resultNode.children.length) {
        return { text: '{}', usesFile: false, description: '' };
    }
    const first = resultNode.children[0];
    const converted = convertNodeToTs(first, 2);
    return { ...converted, description: first.attrs.description || '' };
}
function convertDeclareXmlContentToTs(xmlContent, serviceName = 'ServiceDeclare') {
    const declareNode = parseXml(xmlContent);
    const parametersNode = declareNode.children.find((child) => child.tag === 'parameters');
    const resultNode = declareNode.children.find((child) => child.tag === 'result');
    const parameters = buildParametersType(parametersNode);
    const result = buildResultType(resultNode);
    const namespaceName = toDeclareNamespaceName(serviceName);
    const usesFile = parameters.usesFile || result.usesFile;
    const lines = [];
    if (usesFile) {
        lines.push(`import { File } from "mslib";`);
        lines.push('');
    }
    lines.push(`export namespace ${namespaceName} {`);
    lines.push(`  export namespace $parameters {`);
    lines.push(...buildDescription(parameters.description, 2));
    lines.push(`    export type JsonParam = ${parameters.text};`);
    lines.push(`  }`);
    lines.push('');
    lines.push(`  export namespace $results {`);
    if (result.text !== '{}') {
        lines.push(...buildDescription(result.description, 2));
        lines.push(`    export type Data = ${result.text};`);
    }
    lines.push(`  }`);
    lines.push('');
    lines.push(`  export type Parameters = $parameters.JsonParam;`);
    lines.push(`  export type Result = ${result.text === '{}' ? '{}' : '$results.Data'};`);
    lines.push('}');
    lines.push('');
    lines.push(`export type Parameters = ${namespaceName}.Parameters;`);
    lines.push(`export type Result = ${namespaceName}.Result;`);
    lines.push('');
    return lines.join('\n');
}
async function convertDeclareXmlFileToTs(inputFilePath, outputFilePath, serviceName) {
    const fullPath = path_1.default.resolve(inputFilePath);
    const content = await fs_extra_1.default.readFile(fullPath, 'utf8');
    const tsContent = convertDeclareXmlContentToTs(content, serviceName);
    if (outputFilePath) {
        await fs_extra_1.default.writeFile(path_1.default.resolve(outputFilePath), tsContent, 'utf8');
    }
    return tsContent;
}
//# sourceMappingURL=DeclareXmlToTs.js.map