/**
 * memory-svc — персональная память AI, Enterprise Memory
 * docs/architecture: 01-perplexity-analogue-design.md §2.2.K, §5.9
 * API: GET/POST/DELETE /api/v1/memory
 */

import Fastify from 'fastify';
import cors from '@fastify/cors';
import { eq, and, or, desc } from 'drizzle-orm';
import { db } from './db/index.js';
import { memories } from './db/schema.js';

const PORT = parseInt(process.env.PORT ?? '3010', 10);
const AUTH_SERVICE_URL = process.env.AUTH_SERVICE_URL ?? '';

const app = Fastify({ logger: true });

await app.register(cors, { origin: true });

async function getUserIdFromToken(authHeader: string | undefined): Promise<string | null> {
  if (!authHeader?.startsWith('Bearer ')) return null;
  const token = authHeader.slice(7);
  if (!AUTH_SERVICE_URL) {
    return token ? 'guest' : null;
  }
  try {
    const res = await fetch(`${AUTH_SERVICE_URL.replace(/\/$/, '')}/api/auth/me`, {
      headers: { Authorization: `Bearer ${token}` },
      signal: AbortSignal.timeout(5000),
    });
    if (!res.ok) return null;
    const data = (await res.json()) as { id?: string };
    return data.id ?? null;
  } catch {
    return null;
  }
}

app.get('/health', async () => ({ status: 'ok' }));
app.get('/metrics', async (_req, reply) => {
  reply.header('Content-Type', 'text/plain; charset=utf-8');
  return reply.send('# HELP gooseek_up Service is up (1) or down (0)\n# TYPE gooseek_up gauge\ngooseek_up 1\n');
});
app.get('/ready', async () => ({ status: 'ready' }));

app.get('/api/v1/memory', async (req, reply) => {
  const userId = await getUserIdFromToken(req.headers.authorization);
  if (!userId) {
    return reply.status(401).send({ error: 'Authorization required' });
  }
  const orgId = (req.query as { orgId?: string }).orgId;
  try {
    const conditions = orgId
      ? or(eq(memories.userId, userId), eq(memories.orgId, orgId))
      : eq(memories.userId, userId);
    const list = await db
      .select()
      .from(memories)
      .where(conditions)
      .orderBy(desc(memories.createdAt));
    const items = list.map((r) => ({
      id: r.id,
      key: r.key,
      value: r.value,
      orgId: r.orgId ?? undefined,
      createdAt: r.createdAt?.toISOString?.() ?? r.createdAt,
    }));
    return { items };
  } catch (err) {
    req.log.error(err);
    return reply.status(500).send({ error: 'Failed to fetch memory' });
  }
});

app.post<{
  Body: { key?: string; value?: string; orgId?: string; embedding?: number[] };
}>('/api/v1/memory', async (req, reply) => {
  const userId = await getUserIdFromToken(req.headers.authorization);
  if (!userId) {
    return reply.status(401).send({ error: 'Authorization required' });
  }
  const { key, value, orgId, embedding } = req.body ?? {};
  if (!key?.trim() || !value?.trim()) {
    return reply.status(400).send({ error: 'key and value are required' });
  }
  const id = crypto.randomUUID();
  try {
    await db.insert(memories).values({
      id,
      userId,
      orgId: orgId ?? null,
      key: key.trim(),
      value: value.trim(),
      embedding: embedding ?? null,
    });
    const [inserted] = await db.select().from(memories).where(eq(memories.id, id));
    return reply.status(201).send({
      id: inserted.id,
      key: inserted.key,
      value: inserted.value,
      orgId: inserted.orgId ?? undefined,
      createdAt: inserted.createdAt?.toISOString?.() ?? inserted.createdAt,
    });
  } catch (err) {
    req.log.error(err);
    return reply.status(500).send({ error: 'Failed to create memory' });
  }
});

app.delete<{ Params: { id: string } }>('/api/v1/memory/:id', async (req, reply) => {
  const userId = await getUserIdFromToken(req.headers.authorization);
  if (!userId) {
    return reply.status(401).send({ error: 'Authorization required' });
  }
  const { id } = req.params;
  try {
    const [existing] = await db
      .select()
      .from(memories)
      .where(and(eq(memories.id, id), eq(memories.userId, userId)));
    if (!existing) {
      return reply.status(404).send({ error: 'Memory not found' });
    }
    await db.delete(memories).where(eq(memories.id, id));
    return reply.status(204).send();
  } catch (err) {
    req.log.error(err);
    return reply.status(500).send({ error: 'Failed to delete memory' });
  }
});

try {
  await app.listen({ port: PORT, host: '0.0.0.0' });
  console.log('memory-svc listening on :' + PORT);
} catch (err) {
  console.error(err);
  process.exit(1);
}
