#!/usr/bin/env node

import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { assertValidGeneratedTsx } from './utils/generatedTsxValidator.mjs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const CONFIG = {
  projectRoot: path.resolve(__dirname, '..'),
  pagesDir: path.resolve(__dirname, '../src/prototypes'),
  pendingLogicFileName: '.stitch-pending.json',
  pendingLogicMarker: 'STITCH_PENDING_LOGIC',
};

function log(message, type = 'info') {
  const prefix = { info: '✓', warn: '⚠', error: '✗', progress: '⏳' }[type] || 'ℹ';
  console.log(`${prefix} ${message}`);
}

function ensureDir(dirPath) {
  if (!fs.existsSync(dirPath)) {
    fs.mkdirSync(dirPath, { recursive: true });
  }
}

function sanitizePageName(name) {
  return String(name)
    .replace(/[^a-z0-9-_]/gi, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .toLowerCase();
}

function escapeForTemplateLiteral(value) {
  return String(value)
    .replace(/\\/g, '\\\\')
    .replace(/`/g, '\\`')
    .replace(/\$\{/g, '\\${');
}

function extractTailwindConfig(html) {
  const startMatch = html.match(/tailwind\.config\s*=\s*\{/);
  if (!startMatch) return null;

  const startIndex = startMatch.index + startMatch[0].length - 1;
  let braceCount = 0;
  let endIndex = startIndex;

  for (let i = startIndex; i < html.length; i += 1) {
    if (html[i] === '{') braceCount += 1;
    else if (html[i] === '}') {
      braceCount -= 1;
      if (braceCount === 0) {
        endIndex = i + 1;
        break;
      }
    }
  }

  if (braceCount !== 0) return null;

  const configStr = html.substring(startIndex, endIndex);

  try {
    let cleanedStr = configStr
      .split('\n')
      .map((line) => {
        const commentIndex = line.indexOf('//');
        if (commentIndex >= 0) {
          return line.substring(0, commentIndex).trimEnd();
        }
        return line;
      })
      .join('\n');

    cleanedStr = cleanedStr.replace(/,(\s*[}\]])/g, '$1');
    return (function () {
      return eval(`(${cleanedStr})`);
    }());
  } catch (error) {
    console.error('[Stitch Converter] 解析 Tailwind 配置失败:', error.message);
    return null;
  }
}

function generateTailwindCSS(config) {
  if (!config || !config.theme) return '';

  const theme = config.theme;
  const extend = theme.extend || {};
  let css = '';

  const processColors = (colors, prefix = '') => {
    let colorCSS = '';
    for (const [name, value] of Object.entries(colors)) {
      if (typeof value === 'object' && !Array.isArray(value)) {
        colorCSS += processColors(value, `${prefix}${name}-`);
      } else {
        const cssName = `${prefix}${name}`.replace(/([A-Z])/g, '-$1').toLowerCase();
        colorCSS += `  --color-${cssName}: ${value};\n`;
      }
    }
    return colorCSS;
  };

  if (extend.colors) {
    css += '\n@theme {\n';
    css += processColors(extend.colors);
    css += '}\n';
  }

  if (extend.spacing) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.spacing)) {
      css += `  --spacing-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.fontSize) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.fontSize)) {
      const size = Array.isArray(value) ? value[0] : value;
      css += `  --font-size-${name}: ${size};\n`;
      if (Array.isArray(value) && value[1]) {
        const lineHeight = typeof value[1] === 'object' ? value[1].lineHeight : value[1];
        if (lineHeight) {
          css += `  --line-height-${name}: ${lineHeight};\n`;
        }
      }
    }
    css += '}\n';
  }

  if (extend.fontFamily) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.fontFamily)) {
      const family = Array.isArray(value) ? value.join(', ') : value;
      css += `  --font-family-${name}: ${family};\n`;
    }
    css += '}\n';
  }

  if (extend.borderRadius) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.borderRadius)) {
      const cssName = name === 'DEFAULT' ? 'default' : name;
      css += `  --radius-${cssName}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.boxShadow) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.boxShadow)) {
      const cssName = name === 'DEFAULT' ? 'default' : name;
      css += `  --shadow-${cssName}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.screens) {
    css += '\n/* 自定义断点 */\n';
    for (const [name, value] of Object.entries(extend.screens)) {
      css += `/* @screen ${name}: ${value} */\n`;
    }
  }

  if (extend.zIndex) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.zIndex)) {
      css += `  --z-index-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.opacity) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.opacity)) {
      css += `  --opacity-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.keyframes) {
    css += '\n/* 动画关键帧 */\n';
    for (const [name, frames] of Object.entries(extend.keyframes)) {
      css += `@keyframes ${name} {\n`;
      for (const [percent, styles] of Object.entries(frames)) {
        css += `  ${percent} {\n`;
        for (const [prop, val] of Object.entries(styles)) {
          const cssProp = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
          css += `    ${cssProp}: ${val};\n`;
        }
        css += '  }\n';
      }
      css += '}\n\n';
    }
  }

  if (extend.animation) {
    css += '\n/* 动画工具类 */\n';
    css += '@layer utilities {\n';
    for (const [name, value] of Object.entries(extend.animation)) {
      css += `  .animate-${name} {\n`;
      css += `    animation: ${value};\n`;
      css += '  }\n';
    }
    css += '}\n\n';
  }

  if (extend.transitionDuration) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.transitionDuration)) {
      css += `  --duration-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.transitionTimingFunction) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.transitionTimingFunction)) {
      css += `  --ease-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (extend.backgroundImage) {
    css += '\n@theme {\n';
    for (const [name, value] of Object.entries(extend.backgroundImage)) {
      css += `  --gradient-${name}: ${value};\n`;
    }
    css += '}\n';
  }

  if (config.darkMode) {
    css += `\n/* Dark Mode: ${config.darkMode} */\n`;
  }

  return css;
}

function isTailwindConfigScript(attrs, content) {
  return /tailwind\.config/.test(content) || /id=["']tailwind-config["']/i.test(attrs);
}

function summarizeScript(script) {
  const source = script.content || script.src || '';
  const normalized = source.toLowerCase();

  if (/setinterval|settimeout/.test(normalized) && /time|date|clock/.test(normalized)) {
    return '更新时间或日期显示';
  }
  if (/addEventListener\s*\(\s*['"]click['"]/.test(source) || /\.onclick\s*=/.test(source)) {
    return '点击交互处理';
  }
  if (/addEventListener\s*\(\s*['"]scroll['"]/.test(source)) {
    return '滚动相关行为';
  }
  if (/querySelector|getElementById|textContent|innerHTML/.test(source)) {
    return '页面内容或状态更新';
  }
  if (script.src) {
    return `外部脚本：${script.src}`;
  }

  return '页面动态逻辑';
}

function suggestMigration(script) {
  const source = script.content || script.src || '';
  const normalized = source.toLowerCase();

  if (/setinterval|settimeout/.test(normalized)) {
    return '迁移到 React.useEffect，并在需要时配合 useState 管理显示内容。';
  }
  if (/addEventListener|onclick|onsubmit|onchange/.test(normalized)) {
    return '迁移到组件事件处理函数或 React.useEffect 的事件绑定。';
  }
  if (/querySelector|getElementById|textContent|innerHTML/.test(source)) {
    return '改为通过组件状态、props 或 ref 更新界面，避免直接操作 DOM。';
  }
  if (script.src) {
    return '确认该脚本的用途后，再决定是否以 npm 依赖、按需加载或替代实现接入。';
  }

  return '建议拆解为组件状态、效果函数或独立 helper 后接入。';
}

function createPendingScript(script, index) {
  return {
    id: script.id || `${script.location}-script-${index + 1}`,
    location: script.location,
    src: script.src || null,
    summary: summarizeScript(script),
    suggestedMigration: suggestMigration(script),
    code: script.content || '',
  };
}

function extractHeadContent(html) {
  const headMatch = html.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
  if (!headMatch) return { links: [], styles: [], pendingScripts: [] };

  const headContent = headMatch[1];
  const links = [];
  const styles = [];
  const pendingScripts = [];

  const scriptRegex = /<script([^>]*)>([\s\S]*?)<\/script>/gi;
  let match;
  while ((match = scriptRegex.exec(headContent)) !== null) {
    const attrs = match[1];
    const content = match[2].trim();
    const srcMatch = attrs.match(/src=["']([^"']+)["']/i);

    if (srcMatch) {
      const src = srcMatch[1].replace(/&amp;/g, '&');
      if (src.includes('tailwindcss.com')) continue;
      pendingScripts.push(createPendingScript({
        location: 'head',
        id: attrs.match(/id=["']([^"']+)["']/i)?.[1] || null,
        src,
        content: '',
      }, pendingScripts.length));
      continue;
    }

    if (!content || isTailwindConfigScript(attrs, content)) {
      continue;
    }

    pendingScripts.push(createPendingScript({
      location: 'head',
      id: attrs.match(/id=["']([^"']+)["']/i)?.[1] || null,
      src: null,
      content,
    }, pendingScripts.length));
  }

  const linkRegex = /<link[^>]*>/gi;
  while ((match = linkRegex.exec(headContent)) !== null) {
    const tag = match[0];
    const href = tag.match(/href=["']([^"']+)["']/i)?.[1];
    if (href) {
      links.push({
        href: href.replace(/&amp;/g, '&'),
        rel: tag.match(/rel=["']([^"']+)["']/i)?.[1] || 'stylesheet',
        crossorigin: tag.includes('crossorigin'),
      });
    }
  }

  const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
  while ((match = styleRegex.exec(headContent)) !== null) {
    const content = match[1].trim();
    if (content) {
      styles.push(content);
    }
  }

  return { links, styles, pendingScripts };
}

function convertStyleToJSX(styleStr) {
  if (!styleStr.trim()) return 'style={{}}';

  const styles = [];
  let currentProp = '';
  let inUrl = false;

  for (let i = 0; i < styleStr.length; i += 1) {
    const char = styleStr[i];
    if (char === '(' && styleStr.substring(i - 3, i) === 'url') inUrl = true;
    else if (char === ')' && inUrl) inUrl = false;

    if (char === ';' && !inUrl) {
      if (currentProp.trim()) styles.push(currentProp.trim());
      currentProp = '';
    } else {
      currentProp += char;
    }
  }

  if (currentProp.trim()) styles.push(currentProp.trim());

  const jsxStyles = styles
    .filter((item) => item.includes(':'))
    .map((item) => {
      const colonIndex = item.indexOf(':');
      const key = item.substring(0, colonIndex).trim();
      const value = item.substring(colonIndex + 1).trim();
      if (!key || !value) return '';

      const camelKey = key.replace(/-([a-z])/g, (group) => group[1].toUpperCase());
      let jsxValue;
      if (value.startsWith('url(') || value.includes('var(')) {
        jsxValue = `'${value.replace(/'/g, "\\'")}'`;
      } else if (/^-?\d+(\.\d+)?$/.test(value)) {
        jsxValue = value;
      } else {
        jsxValue = `'${value.replace(/'/g, "\\'")}'`;
      }
      return `${camelKey}: ${jsxValue}`;
    })
    .filter(Boolean)
    .join(', ');

  return `style={{ ${jsxStyles} }}`;
}

function convertCommonAttributesToJSX(content) {
  const replacements = [
    ['class', 'className'],
    ['for', 'htmlFor'],
    ['tabindex', 'tabIndex'],
    ['readonly', 'readOnly'],
    ['maxlength', 'maxLength'],
    ['minlength', 'minLength'],
    ['colspan', 'colSpan'],
    ['rowspan', 'rowSpan'],
    ['viewbox', 'viewBox'],
    ['preserveaspectratio', 'preserveAspectRatio'],
    ['clip-path', 'clipPath'],
    ['fill-rule', 'fillRule'],
    ['clip-rule', 'clipRule'],
    ['stroke-width', 'strokeWidth'],
    ['stroke-dasharray', 'strokeDasharray'],
    ['stroke-dashoffset', 'strokeDashoffset'],
    ['stroke-linecap', 'strokeLinecap'],
    ['stroke-linejoin', 'strokeLinejoin'],
    ['stroke-miterlimit', 'strokeMiterlimit'],
    ['stroke-opacity', 'strokeOpacity'],
    ['fill-opacity', 'fillOpacity'],
    ['stop-color', 'stopColor'],
    ['stop-opacity', 'stopOpacity'],
    ['xlink:href', 'xlinkHref'],
    ['xmlns:xlink', 'xmlnsXlink'],
  ];

  let nextContent = content;
  replacements.forEach(([from, to]) => {
    nextContent = nextContent.replace(new RegExp(`(\\s)${from}=`, 'gi'), `$1${to}=`);
  });

  return nextContent;
}

function convertHtmlToJsx(content) {
  return convertCommonAttributesToJSX(content)
    .replace(/<!--([\s\S]*?)-->/g, '{/* $1 */}')
    .replace(/(<pre[^>]*>)([\s\S]*?)(<\/pre>)/gi, (match, openTag, preContent) => {
      const escapedContent = preContent
        .replace(/\\/g, '\\\\')
        .replace(/`/g, '\\`')
        .replace(/\$/g, '\\$')
        .replace(/\{/g, '\\{');
      return `${openTag.slice(0, -1)} dangerouslySetInnerHTML={{ __html: \`${escapedContent}\` }} />`;
    })
    .replace(/style='([^']*)'/gi, (match, styleStr) => convertStyleToJSX(styleStr))
    .replace(/style="([^"]*)"/gi, (match, styleStr) => convertStyleToJSX(styleStr));
}

function extractBodyContent(html) {
  const bodyMatch = html.match(/(<body[^>]*>)([\s\S]*?)<\/body>/i);
  if (!bodyMatch) {
    return {
      wrapperOpenTag: '<div data-stitch-root="true">',
      jsxContent: '',
      pendingScripts: [],
    };
  }

  const openTag = convertHtmlToJsx(bodyMatch[1])
    .replace(/^<body/i, '<div data-stitch-root="true"');
  const innerContent = bodyMatch[2];
  const pendingScripts = [];

  const contentWithoutScripts = innerContent.replace(/<script([^>]*)>([\s\S]*?)<\/script>/gi, (match, attrs, content) => {
    const trimmedContent = String(content || '').trim();
    pendingScripts.push(createPendingScript({
      location: 'body',
      id: attrs.match(/id=["']([^"']+)["']/i)?.[1] || attrs.match(/data-purpose=["']([^"']+)["']/i)?.[1] || null,
      src: attrs.match(/src=["']([^"']+)["']/i)?.[1]?.replace(/&amp;/g, '&') || null,
      content: trimmedContent,
    }, pendingScripts.length));
    return '';
  });

  return {
    wrapperOpenTag: openTag,
    jsxContent: convertHtmlToJsx(contentWithoutScripts.trim()),
    pendingScripts,
  };
}

function buildPendingSummaryLines(pendingScripts) {
  return pendingScripts.map((item) => `  // - [${item.location}] ${item.id}: ${item.summary}`);
}

function buildPendingEffectBlock(pendingScripts) {
  if (pendingScripts.length === 0) return '';

  const summaryLines = buildPendingSummaryLines(pendingScripts).join('\n');
  return `
  React.useEffect(function () {
    // ${CONFIG.pendingLogicMarker}_START
    // 后续可在这里继续完善页面的动态细节。
    // 参考同目录下的 ${CONFIG.pendingLogicFileName}。
${summaryLines}
    // ${CONFIG.pendingLogicMarker}_END
  }, []);
`;
}

function buildFriendlyNotice() {
  return `
      <div
        className="pointer-events-none fixed right-4 top-4 z-[100] max-w-xs rounded-2xl border border-white/60 bg-white/88 px-4 py-3 text-sm text-slate-700 shadow-lg backdrop-blur"
        style={{ boxShadow: '0 18px 45px rgba(15, 23, 42, 0.12)' }}
      >
        <div className="font-semibold text-slate-900">基础效果已就绪</div>
        <div className="mt-1 leading-6 text-slate-600">
          当前可先查看页面结构与样式效果，部分动态细节可在后续继续完善。
        </div>
      </div>`;
}

function generateComponent(pageName, wrapperOpenTag, bodyJsxContent, headContent, pendingScripts) {
  const componentName = pageName
    .split(/[-_\s]+/)
    .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
    .join('');

  const injectionBlocks = [];

  if (headContent.links.length > 0) {
    injectionBlocks.push(`
  React.useEffect(function () {
    const injected = [];

    ${JSON.stringify(headContent.links)}.forEach(function (linkInfo) {
      const existing = document.querySelector(\`link[href="\${linkInfo.href}"]\`);
      if (!existing) {
        const link = document.createElement('link');
        link.rel = linkInfo.rel;
        link.href = linkInfo.href;
        if (linkInfo.crossorigin) link.crossOrigin = 'anonymous';
        document.head.appendChild(link);
        injected.push(link);
      }
    });

    return function () {
      injected.forEach(function (el) {
        if (el.parentNode) el.parentNode.removeChild(el);
      });
    };
  }, []);
`);
  }

  if (pendingScripts.length > 0) {
    injectionBlocks.push(buildPendingEffectBlock(pendingScripts));
  }

  const friendlyNotice = pendingScripts.length > 0 ? buildFriendlyNotice() : '';
  const wrapperJsx = `${wrapperOpenTag}
${friendlyNotice}
${bodyJsxContent}
    </div>`;

  return `/**
 * @name ${pageName}
 *
 * 参考资料：
 * - /rules/development-guide.md
 * - /skills/default-resource-recommendations/SKILL.md
 */

import './style.css';
import React, { forwardRef, useImperativeHandle } from 'react';
import type { AxureProps, AxureHandle } from '../../common/axure-types';

const Component = forwardRef(function ${componentName}(
  _props: AxureProps,
  ref: React.ForwardedRef<AxureHandle>,
) {
  useImperativeHandle(ref, function () {
    return {
      getVar: function () { return undefined; },
      fireAction: function () {},
      eventList: [],
      actionList: [],
      varList: [],
      configList: [],
      dataList: []
    };
  }, []);
${injectionBlocks.join('')}
  return (
${wrapperJsx.split('\n').map((line) => `    ${line}`).join('\n')}
  );
});

export default Component;
`;
}

function generateStyleCSS(headContent, tailwindConfig) {
  let css = '@import "tailwindcss";\n';

  if (tailwindConfig) {
    css += '\n/* 从 Stitch Tailwind 配置提取的样式 */';
    css += generateTailwindCSS(tailwindConfig);
  }

  if (headContent.styles && headContent.styles.length > 0) {
    css += '\n/* 原始自定义样式 */\n';
    css += headContent.styles.join('\n\n');
  }

  return css;
}

function buildPendingLogicPayload(pageName, outputDir, pendingScripts) {
  const relativeDir = path.relative(CONFIG.projectRoot, outputDir).split(path.sep).join('/');
  const relativeIndexFile = `${relativeDir}/index.tsx`;
  const relativePendingFile = `${relativeDir}/${CONFIG.pendingLogicFileName}`;

  return {
    pageName,
    generatedAt: new Date().toISOString(),
    marker: CONFIG.pendingLogicMarker,
    indexFile: relativeIndexFile,
    pendingFile: relativePendingFile,
    items: pendingScripts,
  };
}

function buildPrompt(pageName, outputDir, pendingPayload) {
  const relativeDir = path.relative(CONFIG.projectRoot, outputDir).split(path.sep).join('/');
  const relativeHtmlFile = `${relativeDir}/code.html`;

  const summaries = pendingPayload.items
    .map((item) => `- [${item.location}] ${item.id}: ${item.summary}。建议：${item.suggestedMigration}`)
    .join('\n');

  return `请继续完善 Stitch 导入后的页面“${pageName}”。

目标目录：
- \`${relativeDir}\`

请优先阅读以下文件：
- \`${relativeDir}/index.tsx\`
- \`${relativeDir}/${CONFIG.pendingLogicFileName}\`
- \`${relativeHtmlFile}\`

当前页面已经可以静态预览，但仍有待完善的动态细节：
${summaries}

请按以下方式处理：
1. 在 \`index.tsx\` 中的 \`${CONFIG.pendingLogicMarker}_START\` / \`${CONFIG.pendingLogicMarker}_END\` 区域附近补入需要的 React 逻辑。
2. 把原始脚本改写为 React 状态、effects、事件处理函数或必要的 helper。
3. 尽量不要直接操作 DOM；优先使用 state、props、ref。
4. 完成逻辑迁移后，补充生成同目录下的 \`spec.md\`，说明页面结构、动态行为和实现要点。
5. 最后运行项目内的可用验收方式，确认页面可正常预览。
`;
}

function convertPage(pagePath, outputDir, pageName) {
  log(`正在转换页面: ${pageName}`, 'progress');

  const htmlPath = path.join(pagePath, 'code.html');
  const html = fs.readFileSync(htmlPath, 'utf8');

  const tailwindConfig = extractTailwindConfig(html);
  const headContent = extractHeadContent(html);
  const bodyContent = extractBodyContent(html);
  const pendingScripts = [...headContent.pendingScripts, ...bodyContent.pendingScripts];

  ensureDir(outputDir);

  const componentCode = generateComponent(
    pageName,
    bodyContent.wrapperOpenTag,
    bodyContent.jsxContent,
    headContent,
    pendingScripts,
  );
  const styleCSS = generateStyleCSS(headContent, tailwindConfig);
  const outputTsxPath = path.join(outputDir, 'index.tsx');

  assertValidGeneratedTsx(componentCode, outputTsxPath);

  fs.writeFileSync(outputTsxPath, componentCode, 'utf8');
  fs.writeFileSync(path.join(outputDir, 'style.css'), styleCSS, 'utf8');

  const pendingPayload = buildPendingLogicPayload(pageName, outputDir, pendingScripts);
  const pendingFilePath = path.join(outputDir, CONFIG.pendingLogicFileName);
  if (pendingScripts.length > 0) {
    fs.writeFileSync(pendingFilePath, `${JSON.stringify(pendingPayload, null, 2)}\n`, 'utf8');
    log(`  ✓ 已整理 ${pendingScripts.length} 段待完善逻辑`, 'info');
  } else if (fs.existsSync(pendingFilePath)) {
    fs.unlinkSync(pendingFilePath);
  }

  log(`页面转换完成: ${pageName}`, 'info');

  return {
    pageName,
    outputDir,
    pendingScripts,
    pendingFile: pendingScripts.length > 0 ? pendingFilePath : null,
    prompt: pendingScripts.length > 0 ? buildPrompt(pageName, outputDir, pendingPayload) : null,
  };
}

function detectProjectType(stitchDir) {
  const items = fs.readdirSync(stitchDir);

  if (items.includes('code.html')) {
    return { type: 'single', prototypes: [{ name: 'index', path: stitchDir }] };
  }

  const prototypes = [];
  for (const item of items) {
    const itemPath = path.join(stitchDir, item);
    const stat = fs.statSync(itemPath);
    if (stat.isDirectory() && fs.existsSync(path.join(itemPath, 'code.html'))) {
      prototypes.push({ name: item, path: itemPath });
    }
  }

  if (prototypes.length > 0) return { type: 'multi', prototypes };
  throw new Error('未找到有效的 Stitch 项目结构');
}

function printResult(result) {
  console.log(JSON.stringify(result));
}

async function main() {
  const args = process.argv.slice(2);

  if (args.length === 0 || args[0] === '--help') {
    console.log(`
使用方法:
  node scripts/stitch-converter.mjs <stitch-dir> [output-name]
    `);
    process.exit(0);
  }

  const stitchDirArg = args[0];
  const outputName = sanitizePageName(args[1] || path.basename(stitchDirArg));
  const stitchDir = path.resolve(CONFIG.projectRoot, stitchDirArg);
  const outputDir = path.join(CONFIG.pagesDir, outputName);

  if (!fs.existsSync(stitchDir)) {
    log(`错误: 找不到目录 ${stitchDir}`, 'error');
    process.exit(1);
  }

  try {
    log('开始转换 Stitch 项目...', 'info');

    const { type, prototypes } = detectProjectType(stitchDir);
    log(`项目类型: ${type === 'single' ? '单页面' : '多页面'}`, 'info');

    if (type === 'single') {
      const pageResult = convertPage(prototypes[0].path, outputDir, outputName);
      const result = {
        success: true,
        type,
        mode: pageResult.pendingScripts.length > 0 ? 'ai_handoff' : 'safe_component',
        pageName: outputName,
        outputDir,
        pendingLogicCount: pageResult.pendingScripts.length,
        requiresAi: pageResult.pendingScripts.length > 0,
        prompt: pageResult.prompt,
        reasons: pageResult.pendingScripts.map((item) => `${item.summary}（${item.location}）`),
      };
      log('✅ 转换完成！', 'info');
      printResult(result);
      return;
    }

    const convertedPages = [];
    for (const page of prototypes) {
      const pageFolderName = sanitizePageName(`${outputName}-${page.name}`);
      const pageOutputDir = path.join(CONFIG.pagesDir, pageFolderName);
      const pageResult = convertPage(page.path, pageOutputDir, page.name);
      convertedPages.push({
        pageName: page.name,
        folderName: pageFolderName,
        outputDir: pageOutputDir,
        pendingLogicCount: pageResult.pendingScripts.length,
        requiresAi: pageResult.pendingScripts.length > 0,
        prompt: pageResult.prompt,
        reasons: pageResult.pendingScripts.map((item) => `${item.summary}（${item.location}）`),
      });
    }

    log('✅ 转换完成！', 'info');
    printResult({
      success: true,
      type,
      mode: convertedPages.some((item) => item.requiresAi) ? 'ai_handoff' : 'safe_component',
      pageName: outputName,
      outputDir,
      pages: convertedPages,
      pendingLogicCount: convertedPages.reduce((sum, item) => sum + item.pendingLogicCount, 0),
      requiresAi: convertedPages.some((item) => item.requiresAi),
      prompt: convertedPages.find((item) => item.prompt)?.prompt || null,
      reasons: convertedPages.flatMap((item) => item.reasons),
    });
  } catch (error) {
    log(`转换失败: ${error.message}`, 'error');
    process.exit(1);
  }
}

if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
  main();
}

export {
  generateComponent,
};
