// Records route — structured records (entry_values composed by a template).
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { createRecord, deleteRecord, getRecord, searchByTemplate, updateRecord } from '../actions/record-crud';

export const recordRoutes = new Hono<{ Bindings: Bindings }>();

// POST /records — { template, values:{slot:content}?, entry_ids:{slot:既有entry_id}?, owner_id? }
//
// values    = 給字串 → **新建**一筆 entry 當這個 slot 的值（原本就有的路，行為不變）
// entry_ids = 給既有 entry 的 id → **指向**水池裡那條 entry，不複製（Arcrun#128 的外鍵）
// 兩者可混用；至少要有一個。**只給 entry_ids 是合法的**——例如一則 wiki 的五段在 KBDB 裡
// 本來就已經是五筆既有 entry，建 record 只是替它們取名字，不該再生出任何新 entry。
const isStringMap = (v: unknown): boolean =>
  !!v && typeof v === 'object' && !Array.isArray(v) && Object.values(v as object).every((x) => typeof x === 'string');

recordRoutes.post('/', async (c) => {
  const body = await c.req.json().catch(() => null);
  if (!body || !body.template || (!body.values && !body.entry_ids)) {
    return c.json({ success: false, error: 'template and values (or entry_ids) required' }, 400);
  }
  if (body.values !== undefined && !isStringMap(body.values)) {
    return c.json({ success: false, error: 'values must be an object of {slot: string}' }, 400);
  }
  if (body.entry_ids !== undefined && !isStringMap(body.entry_ids)) {
    return c.json({ success: false, error: 'entry_ids must be an object of {slot: entry_id}' }, 400);
  }
  try {
    const rec = await createRecord(c.env.DB, body);
    return c.json({ success: true, record: rec });
  } catch (e) {
    return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 400);
  }
});

// GET /records/triplet-stats?owner_id=... — 每個庫的三元組（關聯）數。
// t142（2026-07-29）：政府驗收——顯示每個庫整理出幾條知識關聯。
// 計法：依 triplet 型 record 的 'library' slot 值分組計數。無 library slot 的舊三元組歸 general。
// 使用子查詢先取 distinct triplet record IDs（針對 owner），再 LEFT JOIN library slot，
// 避免 N+1（全部一次 SQL 完成，不逐筆 getRecord）。
recordRoutes.get('/triplet-stats', async (c) => {
  const owner = c.req.query('owner_id') || '';
  // 子查詢：找到屬於這個 owner 的所有 triplet records；LEFT JOIN library slot 取庫名
  const rows = await c.env.DB.prepare(
    `SELECT
       COALESCE(NULLIF(lib_e.content, ''), 'general') AS library,
       COUNT(*) AS triplet_count
     FROM (
       SELECT DISTINCT ev.record_id
       FROM entry_values ev
       JOIN templates t ON ev.template_id = t.id
       JOIN entries e ON ev.entry_id = e.id
       WHERE t.name = 'triplet'
         AND (?1 = '' OR e.owner_id = ?1)
     ) AS tr
     LEFT JOIN entry_values lev
       ON lev.record_id = tr.record_id AND lev.slot_name = 'library'
     LEFT JOIN entries lib_e ON lib_e.id = lev.entry_id
     GROUP BY COALESCE(NULLIF(lib_e.content, ''), 'general')
     ORDER BY library`,
  )
    .bind(owner)
    .all<{ library: string; triplet_count: number }>();
  const stats = (rows.results ?? []).map((r) => ({ library: r.library, triplet_count: r.triplet_count }));
  return c.json({ success: true, stats });
});

// GET /records/by-template/:template — list records of a template
recordRoutes.get('/by-template/:template', async (c) => {
  const records = await searchByTemplate(c.env.DB, c.req.param('template'), c.req.query('owner_id') || undefined);
  return c.json({ success: true, records, count: records.length });
});

// GET /records/:recordId
recordRoutes.get('/:recordId', async (c) => {
  const rec = await getRecord(c.env.DB, c.req.param('recordId'));
  if (!rec) return c.json({ success: false, error: 'not found' }, 404);
  return c.json({ success: true, record: rec });
});

// PATCH /records/:recordId — { values:{slot:content} } update existing record slot values
// (mira-dissolve T2.1 / issue #6; deprecate = flip a slot value, append-only tables untouched).
recordRoutes.patch('/:recordId', async (c) => {
  const body = await c.req.json().catch(() => null);
  if (!body || !body.values || typeof body.values !== 'object') {
    return c.json({ success: false, error: 'values required' }, 400);
  }
  try {
    const rec = await updateRecord(c.env.DB, c.req.param('recordId'), body.values);
    if (!rec) return c.json({ success: false, error: 'not found' }, 404);
    return c.json({ success: true, record: rec });
  } catch (e) {
    return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 400);
  }
});

// DELETE /records/:recordId — 刪除一筆 record 及其底層 entries。
recordRoutes.delete('/:recordId', async (c) => {
  const found = await deleteRecord(c.env.DB, c.req.param('recordId'));
  if (!found) return c.json({ success: false, error: 'not found' }, 404);
  return c.json({ success: true });
});
