import { z } from 'zod';
import type { EcosystemEvent } from './ecosystem.js';

export const TimelineVisibilitySchema = z.enum(['private', 'org', 'shared', 'local-only']);

export const TimelineItemSchema = z.object({
  itemId: z.string().min(1),
  occurredAt: z.string().datetime(),
  eventName: z.string().min(1),
  productId: z.string().min(1),
  title: z.string().min(1),
  summary: z.string().nullable().optional(),
  artifactRefs: z.array(z.string().min(1)),
  relatedEventIds: z.array(z.string().min(1)),
  actorType: z.enum(['user', 'agent', 'system', 'device']),
  visibility: TimelineVisibilitySchema,
  correlationId: z.string().min(1).nullable().optional(),
});

export type TimelineItem = z.infer<typeof TimelineItemSchema>;

type EventLike = Pick<
  EcosystemEvent,
  | 'eventId'
  | 'eventName'
  | 'occurredAt'
  | 'productId'
  | 'artifactId'
  | 'actor'
  | 'trace'
  | 'payload'
>;

function titleForEvent(event: EventLike): string {
  if (event.eventName === 'capture.transcript.created') {
    return 'Transcript captured';
  }
  if (event.eventName === 'memory.entry.created') {
    const kind = typeof event.payload.memoryKind === 'string' ? event.payload.memoryKind : 'memory';
    return `${capitalize(kind)} memory proposed`;
  }
  if (event.eventName === 'artifact.created') {
    const type =
      typeof event.payload.artifactType === 'string' ? event.payload.artifactType : 'artifact';
    const title =
      typeof event.payload.title === 'string' && event.payload.title ? event.payload.title : null;
    return title ? title : `${capitalize(type)} created`;
  }
  if (event.eventName === 'artifact.linked') {
    const relation = typeof event.payload.relation === 'string' ? event.payload.relation : 'linked';
    return `Artifact ${relation}`;
  }
  return event.eventName;
}

function summaryForEvent(event: EventLike): string | null {
  if (event.eventName === 'capture.transcript.created') {
    const duration =
      typeof event.payload.durationMs === 'number'
        ? `${event.payload.durationMs}ms`
        : 'unknown duration';
    const source =
      typeof event.payload.transcriptSource === 'string'
        ? event.payload.transcriptSource
        : 'unknown source';
    return `${source} transcript captured (${duration})`;
  }
  if (event.eventName === 'memory.entry.created') {
    const sources = Array.isArray(event.payload.sourceArtifactIds)
      ? event.payload.sourceArtifactIds.length
      : 0;
    return `${sources} source artifact${sources === 1 ? '' : 's'} linked`;
  }
  if (event.eventName === 'artifact.created') {
    const type =
      typeof event.payload.artifactType === 'string' ? event.payload.artifactType : 'artifact';
    const status = typeof event.payload.status === 'string' ? event.payload.status : 'created';
    return `${type} status: ${status}`;
  }
  if (event.eventName === 'artifact.linked') {
    const target =
      typeof event.payload.targetArtifactId === 'string'
        ? event.payload.targetArtifactId
        : 'unknown target';
    return `Linked to ${target}`;
  }
  return null;
}

function relatedEventIdsForEvent(event: EventLike): string[] {
  return Array.from(
    new Set(
      [event.trace.parentEventId, event.trace.causationId].filter(
        (value): value is string => typeof value === 'string' && value.length > 0
      )
    )
  );
}

export function buildTimelineItem(event: EventLike): TimelineItem {
  return TimelineItemSchema.parse({
    itemId: `timeline_${event.eventId}`,
    occurredAt: event.occurredAt,
    eventName: event.eventName,
    productId: event.productId,
    title: titleForEvent(event),
    summary: summaryForEvent(event),
    artifactRefs: [event.artifactId].filter((value): value is string => Boolean(value)),
    relatedEventIds: relatedEventIdsForEvent(event),
    actorType: event.actor.actorType,
    visibility: 'private',
    correlationId: event.trace.correlationId ?? null,
  });
}

export function buildTimelineItems(events: EventLike[]): TimelineItem[] {
  return events
    .map(buildTimelineItem)
    .sort((left, right) => right.occurredAt.localeCompare(left.occurredAt));
}

function capitalize(value: string): string {
  return value.length === 0 ? value : `${value[0]!.toUpperCase()}${value.slice(1)}`;
}
