$collections */ public function __construct( public int $id, public string $uuid, public ?string $title, public string $model, public array $collections, public int $contextLimit, public int $messageCount, public int $totalTokensInput, public int $totalTokensOutput, public float $totalCostUsd, public \DateTimeImmutable $createdAt, public \DateTimeImmutable $lastActivity, public ?int $authorProfileId = null, ) {} /** * Create from database row with aggregated stats. * * @param array $row */ public static function fromDatabaseRow(array $row): self { return new self( id: (int) $row['id'], uuid: (string) $row['uuid'], title: $row['title'] ?? null, model: (string) ($row['model'] ?? 'unknown'), collections: self::parseCollections($row['collections'] ?? ''), contextLimit: (int) ($row['context_limit'] ?? 3), messageCount: (int) ($row['message_count'] ?? 0), totalTokensInput: (int) ($row['total_tokens_input'] ?? 0), totalTokensOutput: (int) ($row['total_tokens_output'] ?? 0), totalCostUsd: (float) ($row['total_cost_usd'] ?? 0.0), createdAt: new \DateTimeImmutable($row['created_at'] ?? 'now'), lastActivity: new \DateTimeImmutable($row['last_activity'] ?? $row['created_at'] ?? 'now'), authorProfileId: isset($row['author_profile_id']) ? (int) $row['author_profile_id'] : null, ); } /** * Parse comma-separated collections or JSON array. * * @return array */ private static function parseCollections(string|array $collections): array { if (is_array($collections)) { return $collections; } if ($collections === '') { return []; } $decoded = json_decode($collections, true); if (is_array($decoded)) { return $decoded; } return array_filter(array_map('trim', explode(',', $collections))); } /** * Get total tokens used. */ public function totalTokens(): int { return $this->totalTokensInput + $this->totalTokensOutput; } /** * Get display title (with fallback). */ public function displayTitle(): string { return $this->title ?? 'Chat vom ' . $this->createdAt->format('d.m.Y H:i'); } /** * Check if session is active (has recent activity). */ public function isRecentlyActive(int $hoursThreshold = 24): bool { $threshold = new \DateTimeImmutable("-{$hoursThreshold} hours"); return $this->lastActivity > $threshold; } }