<?php

declare(strict_types=1);

namespace App\Framework\EventSourcing\Snapshots;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Database\ConnectionInterface;
use App\Framework\EventSourcing\AggregateId;

/**
 * Database Snapshot Store
 *
 * Stores snapshots in database for persistent storage with version tracking
 */
final readonly class DatabaseSnapshotStore implements SnapshotStore
{
    public function __construct(
        private ConnectionInterface $connection
    ) {
    }

    public function save(SnapshotInterface $snapshot): void
    {
        $this->connection->insert('snapshots', [
            'aggregate_id' => $snapshot->getAggregateId()->toString(),
            'aggregate_class' => $snapshot->getAggregateClass(),
            'version' => $snapshot->getVersion(),
            'state' => json_encode($snapshot->getState()),
            'created_at' => $snapshot->getCreatedAt()->format('Y-m-d H:i:s'),
        ]);
    }

    public function getLatest(AggregateId $aggregateId): ?SnapshotInterface
    {
        $result = $this->connection->query(
            'SELECT * FROM snapshots
             WHERE aggregate_id = ?
             ORDER BY version DESC
             LIMIT 1',
            [$aggregateId->toString()]
        );

        if (empty($result)) {
            return null;
        }

        return $this->hydrateSnapshot($result[0]);
    }

    public function getAtVersion(AggregateId $aggregateId, int $version): ?SnapshotInterface
    {
        $result = $this->connection->query(
            'SELECT * FROM snapshots
             WHERE aggregate_id = ? AND version = ?',
            [$aggregateId->toString(), $version]
        );

        if (empty($result)) {
            return null;
        }

        return $this->hydrateSnapshot($result[0]);
    }

    public function deleteForAggregate(AggregateId $aggregateId): void
    {
        $this->connection->delete('snapshots', [
            'aggregate_id' => $aggregateId->toString(),
        ]);
    }

    public function deleteOlderThan(AggregateId $aggregateId, int $version): void
    {
        $this->connection->exec(
            'DELETE FROM snapshots
             WHERE aggregate_id = ? AND version < ?',
            [$aggregateId->toString(), $version]
        );
    }

    private function hydrateSnapshot(array $row): Snapshot
    {
        // Create appropriate AggregateId subclass
        $aggregateClass = $row['aggregate_class'];
        $aggregateIdClass = $aggregateClass . 'Id';

        if (class_exists($aggregateIdClass)) {
            $aggregateId = new $aggregateIdClass($row['aggregate_id']);
        } else {
            // Fallback to generic AggregateId
            $aggregateId = new class ($row['aggregate_id']) implements \App\Framework\EventSourcing\AggregateId {
                public function __construct(private readonly string $id)
                {
                }

                public function toString(): string
                {
                    return $this->id;
                }
            };
        }

        return new Snapshot(
            aggregateId: $aggregateId,
            version: (int) $row['version'],
            state: json_decode($row['state'], true),
            aggregateClass: $row['aggregate_class'],
            createdAt: Timestamp::fromString($row['created_at'])
        );
    }
}
