import { FastifyInstance } from 'fastify';
import { DbService } from '../services/db.service.js';

export default async function graphRoutes(fastify: FastifyInstance, options: { dbService: DbService }) {
  const { dbService } = options;

  /**
   * GET /api/graph/artists/:id/fusion — fused artist credits for a track or album
   * Query: ?entity_type=track&entity_id=<uuid>
   * Returns the fused view of who is credited as main/featured on this entity.
   */
  fastify.get('/graph/artists/:id/fusion', async (request, reply) => {
    const { id } = request.params as { id: string };
    const query = request.query as { entity_type?: string; entity_id?: string };
    const userId = (request.headers['x-user-id'] as string) || '00000000-0000-0000-0000-000000000000';

    if (query.entity_type === 'track' && query.entity_id) {
      const artists = await dbService.getFusedTrackArtists(query.entity_id, userId);
      return reply.send({ entity_type: 'track', entity_id: query.entity_id, artists });
    }

    return reply.code(400).send({ error: 'Provide ?entity_type=track&entity_id=<uuid>' });
  });

  /**
   * GET /api/graph/tracks/:id/claims — all claims for a track
   */
  fastify.get('/graph/tracks/:id/claims', async (request, reply) => {
    const { id } = request.params as { id: string };
    const userId = (request.headers['x-user-id'] as string) || '00000000-0000-0000-0000-000000000000';

    const claims = await dbService.getClaimsBySubject('track', id, undefined, userId);
    return reply.send({ track_id: id, claims });
  });

  /**
   * GET /api/graph/artists/:id/claims — all claims for an artist
   */
  fastify.get('/graph/artists/:id/claims', async (request, reply) => {
    const { id } = request.params as { id: string };
    const predicate = (request.query as { predicate?: string }).predicate;

    const claims = await dbService.getClaimsBySubject('artist', id, predicate);
    return reply.send({ artist_id: id, claims });
  });

  /**
   * GET /api/graph/artists/:id/beliefs — listener beliefs for an artist
   */
  fastify.get('/graph/artists/:id/beliefs', async (request, reply) => {
    const { id } = request.params as { id: string };
    const userId = (request.headers['x-user-id'] as string) || '00000000-0000-0000-0000-000000000000';

    const beliefs = await dbService.getListenerBeliefs({
      userId,
      entityType: 'artist',
      entityId: id,
    });
    return reply.send({ artist_id: id, beliefs });
  });

  /**
   * POST /api/graph/claim — upsert a claim into the graph
   * Body: { subject_type, subject_id, predicate, object_type, object_id, source, confidence?, raw? }
   */
  fastify.post('/graph/claim', async (request, reply) => {
    const body = request.body as {
      subject_type: string;
      subject_id: string;
      predicate: string;
      object_type: string;
      object_id: string;
      source: string;
      confidence?: number;
      raw?: unknown;
    };
    const userId = (request.headers['x-user-id'] as string) || '00000000-0000-0000-0000-000000000000';

    if (!body.subject_type || !body.subject_id || !body.predicate || !body.object_type || !body.object_id || !body.source) {
      return reply.code(400).send({ error: 'Missing required fields: subject_type, subject_id, predicate, object_type, object_id, source' });
    }

    const id = await dbService.upsertClaim({
      user_id: userId === '00000000-0000-0000-0000-000000000000' ? null : userId,
      subject_type: body.subject_type,
      subject_id: body.subject_id,
      predicate: body.predicate,
      object_type: body.object_type,
      object_id: body.object_id,
      source: body.source,
      confidence: body.confidence,
      raw: body.raw,
    });
    return reply.code(201).send({ id });
  });

  /**
   * POST /api/graph/evidence — record an evidence signal
   * Body: { entity_type, entity_id, signal, profile, weight, context? }
   */
  fastify.post('/graph/evidence', async (request, reply) => {
    const body = request.body as {
      entity_type: string;
      entity_id: string;
      signal: string;
      profile: string;
      weight: number;
      context?: unknown;
    };
    const userId = (request.headers['x-user-id'] as string) || '00000000-0000-0000-0000-000000000000';

    if (!body.entity_type || !body.entity_id || !body.signal || body.weight === undefined) {
      return reply.code(400).send({ error: 'Missing required fields: entity_type, entity_id, signal, weight' });
    }

    const id = await dbService.recordEvidence({
      user_id: userId,
      entity_type: body.entity_type,
      entity_id: body.entity_id,
      signal: body.signal,
      profile: body.profile || 'longterm',
      weight: body.weight,
      context: body.context,
    });
    return reply.code(201).send({ id });
  });

  /**
   * GET /api/graph/sources — list all claim sources and their trust weights
   */
  fastify.get('/graph/sources', async (_request, reply) => {
    const res = await (dbService as any).pgClient.query(
      'SELECT * FROM source_trust ORDER BY trust DESC'
    );
    return reply.send({ sources: res.rows });
  });

  /**
   * GET /api/graph/summary — aggregate graph stats (claim counts per source)
   */
  fastify.get('/graph/summary', async (_request, reply) => {
    const counts = await (dbService as any).pgClient.query(
      `SELECT c.source, st.trust, COUNT(*)::int AS claim_count
       FROM claims c
       JOIN source_trust st ON st.key = c.source
       GROUP BY c.source, st.trust
       ORDER BY claim_count DESC`
    );
    const total = counts.rows.reduce((sum: number, r: any) => sum + r.claim_count, 0);
    return reply.send({ total_claims: total, by_source: counts.rows });
  });
}
