import { NextResponse } from 'next/server';
import { and, eq, desc, inArray } from 'drizzle-orm';

import { withAuth, withPermission } from '@/lib/api/helpers';
import { errorResponse, NotFoundError } from '@/lib/errors';
import { db } from '@/lib/db';
import { interests } from '@/lib/db/schema/interests';
import { auditLogs } from '@/lib/db/schema/system';
import { documents, documentEvents } from '@/lib/db/schema/documents';

interface TimelineEvent {
  id: string;
  type: 'audit' | 'document_event';
  action: string;
  description: string;
  userId: string | null;
  createdAt: Date;
  metadata: Record<string, unknown>;
}

// GET /api/v1/interests/[id]/timeline
export const GET = withAuth(
  withPermission('interests', 'view', async (req, ctx, params) => {
    try {
      const interestId = params.id!;

      const interest = await db.query.interests.findFirst({
        where: and(eq(interests.id, interestId), eq(interests.portId, ctx.portId)),
      });
      if (!interest) throw new NotFoundError('Interest');

      // Fetch audit logs for this interest
      const auditRows = await db
        .select()
        .from(auditLogs)
        .where(
          and(
            eq(auditLogs.entityType, 'interest'),
            eq(auditLogs.entityId, interestId),
          ),
        )
        .orderBy(desc(auditLogs.createdAt))
        .limit(50);

      // Fetch document events for documents linked to this interest
      const interestDocs = await db
        .select({ id: documents.id, title: documents.title })
        .from(documents)
        .where(eq(documents.interestId, interestId));

      const docIds = interestDocs.map((d) => d.id);
      const docEventRows =
        docIds.length > 0
          ? await db
              .select({
                id: documentEvents.id,
                documentId: documentEvents.documentId,
                eventType: documentEvents.eventType,
                eventData: documentEvents.eventData,
                createdAt: documentEvents.createdAt,
              })
              .from(documentEvents)
              .where(inArray(documentEvents.documentId, docIds))
              .orderBy(desc(documentEvents.createdAt))
              .limit(50)
          : [];

      const docTitles = Object.fromEntries(interestDocs.map((d) => [d.id, d.title]));

      // Union and sort
      const auditEvents: TimelineEvent[] = auditRows.map((row) => ({
        id: row.id,
        type: 'audit',
        action: row.action,
        description: buildAuditDescription(row.action, row.newValue as Record<string, unknown> | null),
        userId: row.userId,
        createdAt: row.createdAt,
        metadata: (row.metadata as Record<string, unknown>) ?? {},
      }));

      const docEvents: TimelineEvent[] = docEventRows.map((row) => ({
        id: row.id,
        type: 'document_event',
        action: row.eventType,
        description: `Document "${docTitles[row.documentId] ?? row.documentId}": ${row.eventType}`,
        userId: null,
        createdAt: row.createdAt,
        metadata: (row.eventData as Record<string, unknown>) ?? {},
      }));

      const allEvents = [...auditEvents, ...docEvents];
      allEvents.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());

      return NextResponse.json({ data: allEvents.slice(0, 50) });
    } catch (error) {
      return errorResponse(error);
    }
  }),
);

function buildAuditDescription(
  action: string,
  newValue: Record<string, unknown> | null,
): string {
  if (action === 'create') return 'Interest created';
  if (action === 'archive') return 'Interest archived';
  if (action === 'restore') return 'Interest restored';
  if (action === 'update' && newValue?.pipelineStage) {
    return `Stage changed to "${newValue.pipelineStage}"`;
  }
  if (action === 'update') return 'Interest updated';
  return action;
}
