/* components.jsx — shared atoms + data for 咔嗒Lab homepage directions
   Exports to window: KATA (data), Logo, ThemeToggle, Glyph, Arrow, MonoIndex */

const KATA = {
  nav: ['首页', '社区活动', '企业活动', '技术广场', '社区发帖'],
  modules: [
    { n: '01', key: 'community', title: '社区活动', en: 'Community Events',
      desc: '发现并参与 AI 社区的 Meetup、分享会、工作坊与黑客松，按城市与形式筛选。',
      tag: '开放报名', cta: '浏览活动' },
    { n: '02', key: 'enterprise', title: '企业活动', en: 'Enterprise Hub',
      desc: '关注企业发布会、黑客松与开放日，第一时间了解产业动态。',
      tag: '产业动态', cta: '查看动态' },
    { n: '03', key: 'demo', title: '技术广场', en: 'Tech Playground',
      desc: '体验、调试并交流模型、工具、Skill、数据集与 Agent。',
      tag: '可体验', cta: '去体验' },
    { n: '04', key: 'post', title: '社区发帖', en: 'Open Posts',
      desc: '分享观察、作品与问题，在讨论中找到同行与反馈。',
      tag: '开放讨论', cta: '发布帖子' },
  ],
  events: [
    { date: '05 / 31', day: '周六', title: '多模态 Agent 实战工作坊',
      org: '咔嗒Lab × 上海 AI 社区', mode: '线下 · 上海', tag: 'Workshop', seats: '开放报名' },
    { date: '06 / 04', day: '周三', title: '开源大模型微调线上分享',
      org: 'ModelScope 社区', mode: '线上直播', tag: 'Talk', seats: '可预约' },
    { date: '06 / 08', day: '周日', title: '企业 AI 落地黑客松',
      org: '某头部云厂商 · 开放日', mode: '线下 · 北京', tag: 'Hackathon', seats: '组队中' },
  ],
  /* 早期阶段不展示虚高统计，改用定性信号 */
  stats: [
    { v: '共建', l: '开放社区' },
    { v: '筛选', l: '活动日历' },
    { v: '可跑', l: '技术作品' },
    { v: '讨论', l: '灵感交流' },
  ],
};

function Logo({ height = 26, style = {} }) {
  const R = (typeof window !== 'undefined' && window.__resources) || {};
  return (
    <span className="kata-logo-wrap" style={{ display: 'inline-flex', alignItems: 'center', ...style }}>
      <img className="kata-logo logo-dark" src={R.logoBlack || 'assets/logo-black-trim.png'} alt="咔嗒Lab" style={{ height }} />
      <img className="kata-logo logo-light" src={R.logoWhite || 'assets/logo-white-trim.png'} alt="咔嗒Lab" style={{ height }} />
    </span>
  );
}

function ThemeToggle({ dark, onToggle, className = 'theme-toggle nm-rise-sm' }) {
  return (
    <button className={className} onClick={onToggle} title={dark ? '切换浅色' : '切换深色'} aria-label="theme">
      {dark ? (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <circle cx="12" cy="12" r="4.2" /><path d="M12 2.5v2.4M12 19.1v2.4M4.2 4.2l1.7 1.7M18.1 18.1l1.7 1.7M2.5 12h2.4M19.1 12h2.4M4.2 19.8l1.7-1.7M18.1 5.9l1.7-1.7" />
        </svg>
      ) : (
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
          <path d="M20 14.5A8 8 0 1 1 9.5 4a6.3 6.3 0 0 0 10.5 10.5z" />
        </svg>
      )}
    </button>
  );
}

function Arrow({ size = 15 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round">
      <path d="M3.5 9h11M10 4.5L14.5 9 10 13.5" />
    </svg>
  );
}

/* Geometric module glyphs — built only from squares / circles / lines.
   color comes from currentColor of parent. size in px. */
function Glyph({ type, size = 30, stroke = 2.2 }) {
  const s = size;
  const base = { position: 'absolute', borderColor: 'currentColor', borderStyle: 'solid' };
  const box = { position: 'relative', width: s, height: s };
  if (type === 'community') {
    // three nodes loosely clustered (a community)
    const d = s * 0.34;
    const node = (extra) => ({ ...base, width: d, height: d, borderWidth: stroke, borderRadius: '50%', ...extra });
    return (
      <span className="glyph" style={box}>
        <i style={node({ top: 0, left: s * 0.5 - d / 2 })} />
        <i style={node({ bottom: 0, left: 0 })} />
        <i style={node({ bottom: 0, right: 0 })} />
        <i style={{ ...base, borderWidth: 0, background: 'currentColor', width: stroke, height: s * 0.3, top: s * 0.32, left: s * 0.5 - stroke / 2, transform: 'rotate(0deg)', opacity: .55 }} />
      </span>
    );
  }
  if (type === 'enterprise') {
    // three rising bars (enterprise / growth)
    const bar = (h, x) => ({ ...base, borderWidth: 0, background: 'currentColor', width: s * 0.2, height: h, bottom: 0, left: x, borderRadius: 1 });
    return (
      <span className="glyph" style={box}>
        <i style={bar(s * 0.45, 0)} />
        <i style={{ ...bar(s * 0.7, s * 0.4), opacity: .65 }} />
        <i style={bar(s, s * 0.8)} />
      </span>
    );
  }
  if (type === 'demo') {
    // diamond (model) inside a square frame
    return (
      <span className="glyph" style={box}>
        <i style={{ ...base, borderWidth: stroke, width: s, height: s, borderRadius: 4 }} />
        <i style={{ ...base, borderWidth: stroke, width: s * 0.46, height: s * 0.46, top: s * 0.27, left: s * 0.27, transform: 'rotate(45deg)' }} />
      </span>
    );
  }
  // post — stacked lines + a dot (a feed / open post)
  const line = (w, y) => ({ ...base, borderWidth: 0, background: 'currentColor', height: stroke, width: w, top: y, left: 0, borderRadius: 2 });
  return (
    <span className="glyph" style={box}>
      <i style={{ ...base, borderWidth: stroke, width: s * 0.28, height: s * 0.28, borderRadius: '50%', top: 0, left: 0 }} />
      <i style={line(s * 0.5, s * 0.07)} />
      <i style={{ ...line(s * 0.5, s * 0.2), opacity: .55, left: s * 0.5 }} />
      <i style={line(s, s * 0.55)} />
      <i style={{ ...line(s * 0.7, s * 0.8), opacity: .55 }} />
    </span>
  );
}

function MonoIndex({ children, style = {} }) {
  return <span className="mono" style={{ fontVariantNumeric: 'tabular-nums', ...style }}>{children}</span>;
}

/* ============================================================
   KSITE — content for the live site (home + 4 secondary pages)
   ============================================================ */
const KSITE = {
  /* SPA 使用 hash 路由；保留 .html 旧路径兼容已无必要，统一为 #route */
  nav: [
    { label: '首页', href: '#home', key: 'home' },
    { label: '社区活动', href: '#community', key: 'community' },
    { label: '企业活动', href: '#enterprise', key: 'enterprise' },
    { label: '技术广场', href: '#demo', key: 'demo' },
    { label: '社区发帖', href: '#post', key: 'post' },
  ],

  /* ---- 社区活动集合页 ---- */
  community: {
    cities: ['全部', '北京', '上海', '杭州', '深圳', '成都', '线上'],
    /* 社区主类型固定 4 类：Meetup / 分享会 / 工作坊 / 黑客松；直播归 mode，不占 type */
    types: ['全部', 'Meetup', '分享会', '工作坊', '黑客松'],
    orgs: [
      { name: 'ModelScope 社区', en: 'ModelScope', signal: '开源模型', focus: '模型与工具链' },
      { name: 'Datawhale', en: 'Datawhale', signal: '学习共创', focus: '学习与实践' },
      { name: '上海 AI 俱乐部', en: 'SH AI Club', signal: '线下聚会', focus: '城市 meetup' },
      { name: 'LangChain 中文', en: 'LangChain CN', signal: 'Agent 开发', focus: '应用搭建' },
      { name: '智源社区', en: 'BAAI Hub', signal: '前沿研究', focus: '研究与分享' },
      { name: 'HuggingFace 中文', en: 'HF Chinese', signal: '模型生态', focus: '开源生态' },
    ],
    events: [
      { date: '05 / 31', day: '周六', time: '14:00', title: '多模态 Agent 实战工作坊', org: '咔嗒Lab × 上海 AI 俱乐部', mode: '线下', city: '上海', tag: '工作坊', seats: '开放报名', hot: true },
      { date: '06 / 02', day: '周一', time: '20:00', title: '开源大模型微调线上分享', org: 'ModelScope 社区', mode: '线上', city: '线上', tag: '分享会', seats: '可预约', hot: false },
      { date: '06 / 04', day: '周三', time: '19:30', title: 'RAG 工程化避坑指南', org: 'LangChain 中文', mode: '线上', city: '线上', tag: '分享会', seats: '开放报名', hot: true },
      { date: '06 / 07', day: '周六', time: '13:30', title: 'AI 产品设计 Meetup', org: '智源社区', mode: '线下', city: '北京', tag: 'Meetup', seats: '开放报名', hot: false },
      { date: '06 / 08', day: '周日', time: '10:00', title: '周末黑客松：48 小时造一个 Agent', org: 'Datawhale', mode: '线下', city: '杭州', tag: '黑客松', seats: '组队中', hot: true },
      { date: '06 / 11', day: '周三', time: '20:00', title: '扩散模型从入门到部署', org: 'HuggingFace 中文', mode: '线上', city: '线上', tag: '分享会', seats: '可预约', hot: false },
    ],
  },

  /* ---- 企业活动集合页 ---- */
  enterprise: {
    companies: [
      { name: '智谱 AI', en: 'Zhipu', focus: '中国 · 基座大模型', url: 'https://www.zhipuai.cn' },
      { name: '深度求索 DeepSeek', en: 'DeepSeek', focus: '中国 · 开源推理模型', url: 'https://www.deepseek.com' },
      { name: '月之暗面 Kimi', en: 'Kimi', focus: '中国 · 长上下文', url: 'https://www.moonshot.cn' },
      { name: '阿里通义千问', en: 'Qwen', focus: '中国 · 开源模型族', url: 'https://tongyi.aliyun.com' },
      { name: 'OpenAI', en: 'OpenAI', focus: '美国 · GPT / ChatGPT', url: 'https://openai.com' },
      { name: 'Anthropic', en: 'Anthropic', focus: '美国 · Claude 模型', url: 'https://www.anthropic.com' },
      { name: 'Google DeepMind', en: 'DeepMind', focus: '美国 · Gemini', url: 'https://deepmind.google' },
      { name: 'Meta AI', en: 'Meta', focus: '美国 · Llama 开源', url: 'https://ai.meta.com' },
    ],
    types: ['全部', '发布会', '开发者大会', '黑客松', '训练营', '招聘'],
    events: [
      { date: '06 / 05', title: '新一代基座模型发布会', company: '智谱 AI', type: '发布会', mode: '线上 + 线下', city: '北京', status: '报名中', feat: true },
      { date: '06 / 09', title: '企业 AI 落地黑客松', company: '某头部云厂商', type: '黑客松', mode: '线下', city: '北京', status: '组队中', feat: false },
      { date: '06 / 12', title: '长上下文模型技术开放日', company: '月之暗面', type: '开发者大会', mode: '线下', city: '北京', status: '剩 40 席', feat: true },
      { date: '06 / 15', title: 'Agent 应用训练营 · 第三期', company: '通义实验室', type: '训练营', mode: '线上', city: '线上', status: '预约中', feat: false },
      { date: '06 / 18', title: '多模态能力专场发布', company: 'MiniMax', type: '发布会', mode: '线上', city: '线上', status: '即将开放', feat: false },
      { date: '06 / 21', title: '大模型算法工程师专场', company: '百川智能', type: '招聘', mode: '线下', city: '上海', status: '投递中', feat: false },
    ],
  },

  /* ---- 技术广场 (Hugging Face 式) ---- */
  demo: {
    tabs: ['全部', '模型 Models', '工具 Tools', 'Skills', '数据集', 'Agent'],
    sorts: ['热门', '最新', '趋势', '本周精选'],
    items: [
      { name: '中文长文本摘要 Skill', author: 'lin_ai', org: '林 AI 工作室', type: 'Skill', task: '文本摘要', blurb: '一键把长文档、会议记录浓缩成几句话，省去逐字通读的时间。', likes: '2.4k', runs: '18.2k', updated: '2 天前', hue: 222, trend: true },
      { name: '轻量级文档 OCR 工具', author: 'devkit', org: 'DevKit 团队', type: '工具', task: 'OCR', blurb: '把合同、发票、扫描件里的文字快速提取成可编辑文本。', likes: '1.8k', runs: '9.7k', updated: '6 小时前', hue: 188, trend: false },
      { name: '多工具调用研究助手 Agent', author: 'agent_hub', org: 'AgentHub', type: 'Agent', task: '自主任务', blurb: '能自己查资料、调用工具、分步骤完成任务的 AI 助理。', likes: '3.6k', runs: '21.4k', updated: '今天', hue: 244, trend: true },
      { name: '对话情感分析模型', author: 'nlp_lab', org: 'NLP Lab', type: '模型', task: '文本分类', blurb: '自动识别用户评论、客服对话里的情绪是正面还是负面。', likes: '3.1k', runs: '24.5k', updated: '昨天', hue: 256, trend: false },
      { name: '网页操作浏览器 Agent', author: 'webpilot', org: 'WebPilot', type: 'Agent', task: '浏览器自动化', blurb: '让 AI 像人一样打开网页、点击、填表，自动完成线上流程。', likes: '2.7k', runs: '12.9k', updated: '2 天前', hue: 210, trend: true },
      { name: '语音转写 + 说话人分离', author: 'audio_team', org: '声学团队', type: '模型', task: '语音识别', blurb: '把会议、播客录音转成文字，并自动区分是谁在说话。', likes: '1.2k', runs: '6.3k', updated: '3 天前', hue: 200, trend: false },
      { name: 'PPT 自动生成 Skill', author: 'deck_master', org: 'DeckMaster', type: 'Skill', task: '生成', blurb: '输入一个主题，自动生成结构完整、可继续编辑的演示文稿。', likes: '4.6k', runs: '31.0k', updated: '本周', hue: 232, trend: true },
      { name: '中文指令微调数据集', author: 'open_data', org: '开放数据计划', type: '数据集', task: '指令微调', blurb: '高质量中文问答语料，帮助团队训练更懂中文的模型。', likes: '1.5k', runs: '4.2k', updated: '4 天前', hue: 176, trend: false },
      { name: '图像高清修复 Demo', author: 'pixel_up', org: 'PixelUp', type: '模型', task: '图像增强', blurb: '把模糊、低清的老照片与图片，一键修复到高清效果。', likes: '2.0k', runs: '14.8k', updated: '5 天前', hue: 268, trend: false },
    ],
  },

  /* ---- 社区发帖页 ---- */
  posts: {
    topics: [
      { tag: '#Agent 开发', blurb: '编排与工具调用' },
      { tag: '#RAG 实践', blurb: '检索与工程化' },
      { tag: '#模型微调', blurb: '训练与部署' },
      { tag: '#多模态', blurb: '图文音视频' },
      { tag: '#提示工程', blurb: '指令与流程' },
      { tag: '#求组队', blurb: '项目与合作' },
    ],
    feed: [
      { author: '林深', handle: '@linshen', hue: 222, time: '12 分钟前', kind: '讨论', title: '聊聊 RAG 在长文档场景下的分块策略', body: '最近在做一个法律文书问答，发现固定窗口分块效果一般，换成语义分块后召回明显提升。大家都用什么方案？', tags: ['#RAG 实践', '#Agent 开发'], likes: 86, comments: 24 },
      { author: 'Aria', handle: '@aria_ml', hue: 256, time: '1 小时前', kind: '作品', title: '开源了一个轻量级 Agent 编排框架 🛠️', body: '支持多工具调用与状态回溯，附带可视化调试面板。求 Star，也欢迎一起共建～', tags: ['#Agent 开发', '#求组队'], likes: 214, comments: 57 },
      { author: '陈工', handle: '@chen_dev', hue: 200, time: '3 小时前', kind: '提问', title: '7B 模型微调显存怎么压到 24G 以内？', body: 'LoRA + 4bit 量化之后还是会 OOM，batch 已经降到 1 了。是不是梯度检查点没开对？', tags: ['#模型微调'], likes: 52, comments: 38 },
      { author: '周可', handle: '@zhouke', hue: 268, time: '昨天', kind: '分享', title: '一份多模态论文精读清单（持续更新）', body: '整理了近半年值得读的 20 篇多模态工作，按任务分了类，附我的笔记链接。', tags: ['#多模态'], likes: 168, comments: 19 },
    ],
  },

  pageMeta: {
    community: {
      kicker: 'COMMUNITY · 社区活动',
      title: '发现值得参加的 AI 社区活动',
      desc: 'Meetup、分享会、工作坊与黑客松集中呈现。按城市与形式筛选，找到适合你的下一场活动。'
    },
    enterprise: {
      kicker: 'ENTERPRISE · 企业活动',
      title: '跟进行业里的关键企业动态',
      desc: '发布会、黑客松、开放日与训练营统一入口。关注产业节奏，按需报名与投递。'
    },
    demo: {
      kicker: 'PLAYGROUND · 技术广场',
      title: '体验、调试并交流 AI 技术',
      desc: '发现模型、工具、Skill、数据集与 Agent。看懂它能做什么，再决定是否运行与交流。'
    },
    post: {
      kicker: 'FORUM · 社区讨论',
      title: '把观察、作品与问题写下来',
      desc: '分享实践经验、发布作品进展，或提出具体问题。用清晰的讨论，连接真正相关的人。'
    },
  },
};

/* Per-category icons for 技术广场 (模型/工具/Skill/数据集/Agent) */
function WorkIcon({ type, size = 18, stroke = 2 }) {
  const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
  if (type === '模型') return <svg {...p}><path d="M12 2 2 7l10 5 10-5-10-5Z" /><path d="m2 17 10 5 10-5" /><path d="m2 12 10 5 10-5" /></svg>;
  if (type === '工具') return <svg {...p}><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" /></svg>;
  if (type === 'Skill' || type === 'Skills') return <svg {...p}><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></svg>;
  if (type === '数据集') return <svg {...p}><ellipse cx="12" cy="5" rx="9" ry="3" /><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5" /><path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3" /></svg>;
  if (type === 'Agent') return <svg {...p}><rect x="3" y="11" width="18" height="10" rx="2.5" /><circle cx="12" cy="5" r="2" /><path d="M12 7v4" /><circle cx="9" cy="16" r="1" /><circle cx="15" cy="16" r="1" /></svg>;
  return <svg {...p}><rect x="4" y="4" width="16" height="16" rx="4" /><path d="M9 12h6M12 9v6" /></svg>;
}

Object.assign(window, { KATA, KSITE, Logo, ThemeToggle, Arrow, Glyph, WorkIcon, MonoIndex });
