import { Hono } from 'hono';
import { db } from '../db';
import { ledgers as ledgersTable } from '../db/schema';
import { eq } from 'drizzle-orm';

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
const MAX_NAME_LENGTH = 200;
const MAX_ENCRYPTED_DATA_LENGTH = 1_048_576; // 1 MiB

const ledgers = new Hono();

// POST /ledgers — create a new ledger
ledgers.post('/', async (c) => {
  let body: Record<string, unknown>;
  try {
    body = await c.req.json();
  } catch {
    return c.json({ error: 'Request body must be valid JSON' }, 400);
  }

  let { id, name, encryptedData } = body;

  // Auto-generate id if missing or invalid — the server is the authority
  if (!id || typeof id !== 'string' || !UUID_RE.test(id)) {
    id = crypto.randomUUID();
  }
  if (!name || typeof name !== 'string' || name.trim().length === 0) {
    return c.json({ error: 'name is required and must be a non-empty string' }, 400);
  }
  if (name.length > MAX_NAME_LENGTH) {
    return c.json({ error: `name must be at most ${MAX_NAME_LENGTH} characters` }, 400);
  }
  if (!encryptedData || typeof encryptedData !== 'string') {
    return c.json({ error: 'encryptedData is required and must be a base64 string' }, 400);
  }
  if (encryptedData.length > MAX_ENCRYPTED_DATA_LENGTH) {
    return c.json({ error: `encryptedData must be at most ${MAX_ENCRYPTED_DATA_LENGTH} bytes` }, 400);
  }

  await db.insert(ledgersTable).values({
    id,
    name: name.trim(),
    encryptedData: Buffer.from(encryptedData, 'base64'),
  });

  return c.json({ id, name: name.trim() }, 201);
});

// GET /ledgers/:id — read a ledger
ledgers.get('/:id', async (c) => {
  const id = c.req.param('id');

  const result = await db.query.ledgers.findFirst({
    where: eq(ledgersTable.id, id),
  });

  if (!result) {
    return c.json({ error: 'Not found' }, 404);
  }

  return c.json({
    id: result.id,
    name: result.name,
    encryptedData: result.encryptedData.toString('base64'),
    createdAt: result.createdAt,
    updatedAt: result.updatedAt,
  });
});

// PUT /ledgers/:id — update a ledger
ledgers.put('/:id', async (c) => {
  const id = c.req.param('id');
  const body = await c.req.json();
  const { encryptedData } = body;

  await db
    .update(ledgersTable)
    .set({
      encryptedData: Buffer.from(encryptedData, 'base64'),
      updatedAt: new Date(),
    })
    .where(eq(ledgersTable.id, id));

  return c.json({ id, updatedAt: new Date().toISOString() });
});

// DELETE /ledgers/:id — delete a ledger
ledgers.delete('/:id', async (c) => {
  const id = c.req.param('id');

  const result = await db.query.ledgers.findFirst({
    where: eq(ledgersTable.id, id),
    columns: { id: true },
  });

  if (!result) {
    return c.json({ error: 'Not found' }, 404);
  }

  await db.delete(ledgersTable).where(eq(ledgersTable.id, id));
  return c.json({ id, deleted: true });
});

export { ledgers };
