import { readFileSync, existsSync, readdirSync, statSync } from "fs";
import { join, basename } from "path";
// Extract props from Vue component script
function extractProps(content) {
    const props = [];
    // Vue 3 Composition API: defineProps<{...}>() with TypeScript generics
    // Handles both withDefaults(defineProps<{...}>(), {...}) and defineProps<{...}>()
    const definePropsMatch = content.match(/defineProps<\{([\s\S]*?)\}>\s*\(\)/);
    if (definePropsMatch) {
        const propsContent = definePropsMatch[1];
        // Extract defaults from withDefaults if present
        const defaultsMatch = content.match(/withDefaults\s*\(\s*defineProps<[\s\S]*?>\s*\(\)\s*,\s*\{([\s\S]*?)\}\s*\)/);
        const defaultsContent = defaultsMatch ? defaultsMatch[1] : "";
        // Parse each prop with its JSDoc comment
        // Pattern: /** comment */ propName?: type;
        const propRegex = /(?:\/\*\*[\s\S]*?\*\/\s*)?(\w+)(\?)?:\s*([^;]+);/g;
        let match;
        while ((match = propRegex.exec(propsContent)) !== null) {
            const propName = match[1];
            const isOptional = !!match[2];
            const propType = match[3].trim();
            // Extract description from JSDoc comment before this prop
            const beforeProp = propsContent.substring(0, match.index);
            const jsdocMatch = beforeProp.match(/\/\*\*\s*([\s\S]*?)\s*\*\/\s*$/);
            let description;
            if (jsdocMatch) {
                description = jsdocMatch[1]
                    .replace(/^\s*\*\s*/gm, "")
                    .replace(/\n/g, " ")
                    .trim();
            }
            // Extract default value
            const defaultMatch = defaultsContent.match(new RegExp(`${propName}\\s*:\\s*['"\`]?([^'"\`,}]+)['"\`]?`));
            const defaultValue = defaultMatch ? defaultMatch[1].trim() : undefined;
            // Extract options from union types like 'a' | 'b' | 'c'
            let options;
            const unionMatch = propType.match(/^['"]([^'"]+)['"](?:\s*\|\s*['"]([^'"]+)['"])+$/);
            if (unionMatch || (propType.includes("'") && propType.includes("|"))) {
                options = propType
                    .split("|")
                    .map((s) => s.trim().replace(/['"]/g, ""))
                    .filter((s) => s.length > 0);
            }
            props.push({
                name: propName,
                type: propType,
                required: !isOptional,
                defaultValue,
                options,
                description,
            });
        }
    }
    // Fallback: Options API props: { ... }
    if (props.length === 0) {
        const propsMatch = content.match(/props\s*:\s*{([\s\S]*?)}\s*(?:,|\n\s*\w)/);
        if (propsMatch) {
            const propsContent = propsMatch[1];
            const propRegex = /(\w+)\s*:\s*{([^}]*)}/g;
            let match;
            while ((match = propRegex.exec(propsContent)) !== null) {
                const propName = match[1];
                const propDef = match[2];
                const prop = { name: propName };
                const typeMatch = propDef.match(/type\s*:\s*(\w+)/);
                if (typeMatch)
                    prop.type = typeMatch[1].toLowerCase();
                const defaultMatch = propDef.match(/default\s*:\s*(?:['"`]([^'"`]*)['"`]|(\w+))/);
                if (defaultMatch)
                    prop.defaultValue = defaultMatch[1] || defaultMatch[2];
                const requiredMatch = propDef.match(/required\s*:\s*(true|false)/);
                if (requiredMatch)
                    prop.required = requiredMatch[1] === "true";
                const validatorMatch = propDef.match(/validator\s*:\s*\(?\w+\)?\s*=>\s*\[([^\]]+)\]/);
                if (validatorMatch) {
                    prop.options = validatorMatch[1].split(",").map((s) => s.trim().replace(/['"`]/g, ""));
                }
                props.push(prop);
            }
        }
    }
    // Fallback: TypeScript interface-based props
    if (props.length === 0) {
        const interfaceMatch = content.match(/interface\s+\w*Props\w*\s*{([\s\S]*?)}/);
        if (interfaceMatch) {
            const interfaceContent = interfaceMatch[1];
            const propRegex = /(\w+)(\?)?:\s*([^;\n]+)/g;
            let match;
            while ((match = propRegex.exec(interfaceContent)) !== null) {
                props.push({
                    name: match[1],
                    type: match[3].trim(),
                    required: !match[2],
                });
            }
        }
    }
    return props;
}
// Extract slots from template
function extractSlots(content) {
    const slots = [];
    const seenSlots = new Set();
    // Match <slot> tags
    const slotRegex = /<slot\s*(?:name=["']([^"']+)["'])?[^>]*>/g;
    let match;
    while ((match = slotRegex.exec(content)) !== null) {
        const slotName = match[1] || "default";
        if (!seenSlots.has(slotName)) {
            seenSlots.add(slotName);
            slots.push({ name: slotName });
        }
    }
    return slots;
}
// Extract emitted events
function extractEvents(content) {
    const events = [];
    const seenEvents = new Set();
    // Match emit calls
    const emitPatterns = [
        /emit\s*\(\s*['"`]([^'"`]+)['"`]/g,
        /\$emit\s*\(\s*['"`]([^'"`]+)['"`]/g,
        /defineEmits\s*<?\s*\[?\s*['"`]([^'"`\]]+)['"`]/g,
    ];
    for (const pattern of emitPatterns) {
        let match;
        while ((match = pattern.exec(content)) !== null) {
            const eventName = match[1];
            if (!seenEvents.has(eventName)) {
                seenEvents.add(eventName);
                events.push({ name: eventName });
            }
        }
    }
    // Match emits option
    const emitsMatch = content.match(/emits\s*:\s*\[([\s\S]*?)\]/);
    if (emitsMatch) {
        const emitsContent = emitsMatch[1];
        const eventRegex = /['"`]([^'"`]+)['"`]/g;
        let match;
        while ((match = eventRegex.exec(emitsContent)) !== null) {
            if (!seenEvents.has(match[1])) {
                seenEvents.add(match[1]);
                events.push({ name: match[1] });
            }
        }
    }
    return events;
}
// Extract CSS classes from component
function extractCssClasses(content) {
    const classes = [];
    const seenClasses = new Set();
    // Match mc- prefixed classes (Mozaic convention)
    const classRegex = /['"`](mc-[a-z0-9-]+)['"`]/g;
    let match;
    while ((match = classRegex.exec(content)) !== null) {
        if (!seenClasses.has(match[1])) {
            seenClasses.add(match[1]);
            classes.push(match[1]);
        }
    }
    return classes;
}
function parseVueFile(filePath) {
    try {
        const content = readFileSync(filePath, "utf-8");
        const fileName = basename(filePath, ".vue");
        return {
            name: fileName,
            props: extractProps(content),
            slots: extractSlots(content),
            events: extractEvents(content),
        };
    }
    catch (error) {
        console.warn(`Warning: Could not parse ${filePath}:`, error);
        return null;
    }
}
// Parse storybook stories for examples
function parseStoriesFile(filePath) {
    const examples = [];
    try {
        const content = readFileSync(filePath, "utf-8");
        // Match story exports
        const storyRegex = /export\s+const\s+(\w+)[\s\S]*?args\s*:\s*{([^}]*)}/g;
        let match;
        while ((match = storyRegex.exec(content)) !== null) {
            const storyName = match[1];
            const args = match[2];
            // Skip Default story as it's usually just basic usage
            if (storyName !== "Default") {
                examples.push({
                    title: storyName.replace(/([A-Z])/g, " $1").trim(),
                    code: args.trim(),
                });
            }
        }
        // Also try to extract template strings
        const templateRegex = /template\s*:\s*`([^`]+)`/g;
        while ((match = templateRegex.exec(content)) !== null) {
            examples.push({
                title: "Example",
                code: match[1].trim(),
            });
        }
    }
    catch (error) {
        console.warn(`Warning: Could not parse stories ${filePath}:`, error);
    }
    return examples;
}
function findComponentDirs(baseDir) {
    const dirs = [];
    if (!existsSync(baseDir)) {
        return dirs;
    }
    const entries = readdirSync(baseDir);
    for (const entry of entries) {
        const fullPath = join(baseDir, entry);
        const stat = statSync(fullPath);
        // Accept directories that are lowercase component names (not .mdx files, etc.)
        if (stat.isDirectory() && /^[a-z]/.test(entry)) {
            dirs.push(fullPath);
        }
    }
    return dirs;
}
// Component category mapping based on name patterns
function inferCategory(componentName) {
    const name = componentName.toLowerCase();
    if (["button", "link", "optionbutton", "optioncard"].some((n) => name.includes(n))) {
        return "action";
    }
    if ([
        "input",
        "select",
        "checkbox",
        "radio",
        "toggle",
        "textarea",
        "field",
        "autocomplete",
        "datepicker",
        "dropdown",
        "fileuploader",
        "password",
        "phone",
        "quantity",
    ].some((n) => name.includes(n))) {
        return "form";
    }
    if (["accordion", "breadcrumb", "menu", "pagination", "sidebar", "stepper", "tabs"].some((n) => name.includes(n))) {
        return "navigation";
    }
    if (["badge", "flag", "loader", "modal", "notification", "progress", "tooltip"].some((n) => name.includes(n))) {
        return "feedback";
    }
    if (["card", "divider", "layer"].some((n) => name.includes(n))) {
        return "layout";
    }
    if (["table", "heading", "hero", "listbox", "rating", "tag"].some((n) => name.includes(n))) {
        return "data-display";
    }
    return "other";
}
export async function parseVueComponents(componentsPath) {
    const components = [];
    const componentDirs = findComponentDirs(componentsPath);
    for (const dir of componentDirs) {
        const dirName = basename(dir);
        // Convert directory name to PascalCase with M prefix (button -> MButton)
        const componentName = "M" + dirName.charAt(0).toUpperCase() + dirName.slice(1);
        // Try multiple file patterns
        const possibleFiles = [
            join(dir, `${componentName}.vue`), // MButton.vue
            join(dir, `${dirName}.vue`), // button.vue
            join(dir, "index.vue"), // index.vue
        ];
        let vueFile = null;
        for (const file of possibleFiles) {
            if (existsSync(file)) {
                vueFile = file;
                break;
            }
        }
        if (vueFile) {
            const parsed = parseVueFile(vueFile);
            if (parsed) {
                const component = {
                    name: parsed.name,
                    slug: parsed.name.replace(/^M/, "").toLowerCase(),
                    category: inferCategory(parsed.name),
                    frameworks: ["vue"],
                    props: parsed.props,
                    slots: parsed.slots,
                    events: parsed.events,
                    examples: [],
                    cssClasses: [],
                };
                // Try to find stories file - check both in component dir and stories subdir
                const storyPatterns = [
                    join(dir, `${componentName}.stories.ts`), // MButton.stories.ts
                    join(dir, `${dirName}.stories.ts`), // button.stories.ts
                    join(dir, "stories", `${componentName}.stories.ts`),
                    join(dir, "stories", "index.stories.ts"),
                ];
                for (const storyPath of storyPatterns) {
                    if (existsSync(storyPath)) {
                        const stories = parseStoriesFile(storyPath);
                        component.examples?.push(...stories.map((s) => ({
                            framework: "vue",
                            title: s.title,
                            code: s.code,
                        })));
                        break; // Use first found stories file
                    }
                }
                // Also check for stories directory with multiple files
                const storiesDir = join(dir, "stories");
                if (existsSync(storiesDir)) {
                    const storyFiles = readdirSync(storiesDir).filter((f) => f.endsWith(".stories.ts"));
                    for (const storyFile of storyFiles) {
                        const stories = parseStoriesFile(join(storiesDir, storyFile));
                        component.examples?.push(...stories.map((s) => ({
                            framework: "vue",
                            title: s.title,
                            code: s.code,
                        })));
                    }
                }
                // Extract CSS classes from the Vue file
                const vueContent = readFileSync(vueFile, "utf-8");
                component.cssClasses = extractCssClasses(vueContent);
                components.push(component);
            }
        }
    }
    return components;
}
//# sourceMappingURL=vue-parser.js.map