import { getCollection } from 'astro:content';
import cards from '../data/cards.json';
import mangaCards from '../data/mangaCards.json';
import englishCards from '../data/englishCards.json';

export type Card = { day: string; series: string; published: string; title: string; slug: string; cover: string | null; thumb: string | null };
export type MangaCard = { slug: string; title: string; label: string; character: string; description: string; published: string; cover: string; comic: string; cover_alt: string; comic_alt: string };

// 一覧に並べる記事：Claude が書いた Markdown の記事 ＋ Studio から移した記事
// 並び順は LOG 番号の大きい順（1日に何本も出すようになり、公開日時の順だと番号と前後することがあるため）。
// 番号が同じか取れないもの（英語版の LOG187EN など）は公開日時で並べる
export async function allCards(): Promise<Card[]> {
  const md = (await getCollection('records')).map((e) => ({
    day: `LOG${e.data.day}`, series: e.data.series, published: e.data.date.toISOString(),
    title: e.data.title, slug: e.data.slug, cover: e.data.cover ?? null, thumb: e.data.cover ? null : `/thumbs/LOG${e.data.day}.html`,
  }));
  const seen = new Set(md.map((c) => c.slug));
  const studio = (cards as Card[]).filter((c) => !seen.has(c.slug));
  const num = (c: Card) => { const m = /^LOG(\d+)/.exec(c.day); return m ? Number(m[1]) : -1; };
  return [...md, ...studio].sort((a, b) => (num(b) - num(a)) || b.published.localeCompare(a.published));
}

export async function seriesCards(series: string): Promise<Card[]> {
  return (await allCards()).filter((c) => c.series === series);
}

export const allManga = mangaCards as MangaCard[];
export const allEnglish = englishCards as MangaCard[];

// 試算のタブ（シリーズのページの Simulator）。task は何をするロボットか、place はどこで使うか。
// 1つ目は sim.src・sim.title・sim.note・sim.obs をそのまま使う。2つ目からは src に # で現場を付ける
// img はタブに出す写真（public/site/sim/ に置く。なければ文字だけ）
export type SimTab = { id: string; task: string; place: string; src: string; title: string; note: string; img?: string };

// シリーズのページ（URL → 記事のシリーズ名）。Studio の一覧の絞り込み条件と同じ
// intro はシリーズのページの見出しの下に出す説明（ないシリーズは出さない）
export const SERIES_PAGES: Record<string, { series: string; title: string; pageTitle: string; limit: number; intro?: string; points?: { h: string; items: string[] }[]; guide?: boolean; thinking?: boolean; serving?: boolean; sim?: { src: string; title: string; note: string; obs?: { src: string; title: string; label: string; note: string; points: string[] }; tabs?: SimTab[] } }> = {
  series1: { series: 'HRI', title: 'Drug Delivery Robot | 薬剤搬送ロボットハコブくん', pageTitle: 'Series1 | 薬剤搬送ロボット', limit: 12,
    intro: '病院で薬を運ぶロボット「ハコブくん」を題材に、人とロボットの関わり（HRI）を設計している記録です。病院で使う画面（UI）の設計、Unity での自律移動、Fusion での形づくり、分身ロボット（アバター）の考察までを、4コママンガと一緒に残しています。' },
  series2: { series: 'R2R2R', title: 'R2R2R | デジタルツイン学習-R2R2R（Real to Render to Real）', pageTitle: 'Series2 | R2R2R', limit: 12,
    intro: 'iPhone で物を3Dスキャンし、Unity の中で動きを試してから、机の上のロボットアーム（mechArm 270）で実際に動かす記録です。ロボット工学を専門に学んでいないデザイナーでも、アームのつかむ・渡すといった動きを設計できるかを、失敗も含めて残しています。' },
  series3: { series: 'UV-C農業ロボット', title: 'UV-C Agricultural Robot | UV-C農業ロボット', pageTitle: 'Series3 | UV-C農業ロボット', limit: 20,
    intro: '湿気の多い日本の農業で、紫外線（UV-C）を当てて作物の病気を抑えるロボットが何を変えるかを考えた記録です。フィジカルAIを使った農業を、製造業のように管理する仕組みとして捉え直しています。' },
  series4: { series: 'ひとり研究所の裏側', title: 'Behind the Solo Lab | ひとり研究所の裏側', pageTitle: 'Series4 | ひとり研究所の裏側', limit: 12,
    intro: 'フィジカルAIの研究をひとりで続けるために、AIと一緒に作ってきた仕組みの記録です。サイトの移行、動画の制作、記録の整理など、研究の外側の作業をどう回しているかを残しています。' },
  series5: { series: '考察記事', title: 'Deep Dive | 考察記事', pageTitle: 'Series5 | 考察記事', limit: 12, thinking: true,
    intro: '実装の記録とは別に、フィジカルAIやロボットについて、なぜそうなるのか、何を意味するのかを考えた記事です。論文や企業の発表、市場の動きを読み、対話の形で考えたことを、外れた議論も含めてそのまま残しています。' },
  series6: { series: 'フィジカルAI研究室', title: 'Physical AI Lab | フィジカルAI研究室', pageTitle: 'Series6 | フィジカルAI研究室', limit: 12, guide: true,
    intro: 'ロボットアームが動きを覚える環境を、自宅にひとりで作っている記録です。机の上のアームでお手本の動きを集め、ロボット用のAI（Physical Intelligence の π0.5 など）に学習させ、実機で動かして確かめます。借りたGPUの種類・時間・費用も含めて、誰でも同じ手順で始められる形で残しています。' },
  series7: { series: '画像認識・物体検出', title: 'Image recognition and Object detection | 画像認識と物体検出', pageTitle: 'Series7 | 画像認識と物体検出', limit: 12,
    intro: 'ロボットのカメラが物を見つける仕組みを、下の層から学び直している記録です。画素の数字、色の見分け方、しきい値、輪郭、特徴点といった昔からの手法を、机の上のアームを撮った写真で1つずつ測って確かめ、その上で SAM 3 のような新しいモデルも試します。評価の物差し（IoU・適合率・再現率など）を先に決め、結果は数字で残しています。' },
  series8: { series: '導入シミュレーション', title: 'Service Robot Simulation | サービスロボット導入シミュレーション', pageTitle: 'Series8 | サービスロボット導入シミュレーション', limit: 12, serving: true,
    intro: 'サービスロボット導入シミュレーションとは、配膳・清掃・搬送などのロボットを店や施設に入れる前に、待ち時間・必要な人数・ロボットが止まる場所・費用を試算して確かめることです。このシリーズでは、時間・順番・台数を SimPy で、ぶつかる・こぼれるといった空間と動きを Unity で扱い、結果とコードを全量公開しています。',
    // 見出しの下に並べる短い一覧（検索や AI が「何が分かるか・どう試算するか」を拾えるように、本文の文字で書く）
    points: [
      { h: 'シミュレーションで分かること', items: ['必要な人数：ロボットを何台入れれば、スタッフを何人減らせるか', '待ち時間：ピーク時の入店待ちと、料理が届くまでの時間', '止まる場所：通路や席の配置で、ロボットが詰まる箇所', '費用：ロボットの月額と、浮く人件費の比較（補助金を含む）'] },
      { h: '試算の方法', items: ['時間・順番・台数：離散イベントシミュレーション（SimPy）', '空間と動き：3Dシミュレーション（Unity）', '前提の数字：公開事例と、店で数える観察シート', 'ブラウザで試せる試算：飲食店・病院・商業施設・ホテル・オフィス・屋外の6現場'] },
    ],
    sim: { src: '/sim/serving-robot.html', title: '配膳ロボット、何台入れたら店は変わる？',
      note: '店を選び、人数・台数・ロボットの使い方を切り替えると、ピーク時の入店待ちや料理が届くまでの時間が変わります。標準ファミレスは、店の形（平面図）から選ぶこともできます。レジの数（1つ・2つ）も選べます。ロボットの費用と浮く人件費も比べられます（補助金の情報つき）。1つの条件を40回回した平均で、数字はすべて仮の前提による試算です（試作 v2.8・32,850条件）。',
      obs: { src: '/sim/serving-robot-observation.html', title: '試算の仮の数字を、店で数える観察シート', label: '観察シートを開く ↗',
        note: '配膳ロボットが通路で何回止まるかは、公開データが見つかりませんでした。店で片手で押して数えるための記録シートの例です。押した記録はこのブラウザの中にだけ保存され、どこにも送られません。',
        points: ['ロボットの出発・卓に着いた・止まった・戻ったを押すと、1往復の時間と止まった割合が出る', '止まった場所と原因を選べる。選択肢は記録する人の立場（客席から・店のスタッフ・導入や保守の担当）で切り替わる', '地図やルートを変える前と後の観察を並べて比べられる'] },
      tabs: [
        { id: 'serving', img: '/site/sim/serving.jpg?v=2', task: '配膳', place: '飲食店', src: '/sim/serving-robot.html', title: '', note: '' },
        { id: 'hospital', img: '/site/sim/hospital.jpg?v=1', task: '搬送', place: '病院', src: '/sim/service-robot-sites.html#hospital', title: '検体と薬剤の搬送、ロボットに任せると何が変わる？',
          note: '慈恵医大柏病院の公開事例の形（3つのルート・運行の時間帯・同じ階）をもとに、病院の広さを選び、人が運ぶ時間と、荷物が届くまでの時間を比べます。ロボットが途中で止まる割合など、公開されていない値は仮置きで、何段階か動かせます（試作 v1・3,276条件・各30回の平均）。' },
        { id: 'cleaning', img: '/site/sim/cleaning.jpg?v=2', task: '清掃', place: '商業施設・ビル', src: '/sim/service-robot-sites.html#cleaning', title: '夜間の床清掃、人の作業はどれだけ減る？',
          note: '施設の広さ・ロボットが拭ける広い床の割合・台数・引っかかる回数を切り替えると、人の作業時間と、ロボットに呼ばれる回数が変わります。施設全体で5%減と対象エリアで60%減という公開事例の差を、床の割合で確かめられます（試作 v1・5,840条件・各30回の平均）。' },
        { id: 'hotel', img: '/site/sim/hotel.jpg?v=2', task: '配送', place: 'ホテル', src: '/sim/service-robot-sites.html#hotel', title: 'アメニティの客室配送、フロントは楽になる？',
          note: 'ホテルの広さ（120室・200室・400室）を選び、客室からの依頼をロボットで届けると、フロントを離れる時間・届くまでの時間・チェックインの待ちがどう変わるかを比べます（試作 v1・2,379条件・各30回の平均）。' },
        { id: 'security', img: '/site/sim/security.jpg?v=1', task: '巡回', place: 'オフィスビル', src: '/sim/service-robot-sites.html#security', title: '夜間の警備、巡回をロボットに任せると？',
          note: 'ビルの広さを選び、ロボットが巡回して異常を知らせ、警備員が駆けつける形で、異常に人が着くまでの時間と、防災センターが空く時間を比べます。異常でないものを知らせる空振りの回数は仮置きです（試作 v1・1,674条件・各30回の平均）。' },
        { id: 'outdoor', img: '/site/sim/outdoor.jpg?v=2', task: '配送', place: '屋外（歩道）', src: '/sim/service-robot-sites.html#outdoor', title: '歩道の配送ロボット、何件から人が足りなくなる？',
          note: '店から家へ届けるロボットと遠隔のオペレーターで、配達エリアの広さ・注文の数・台数・1人が見られる台数を切り替えます。止まってオペレーターを呼ぶ回数は仮置きです（試作 v1・3,960条件・各30回の平均）。' },
      ] } },
};
