<?php

declare(strict_types=1);

namespace Bot\Infrastructure\Repository\Database;

use Bot\Domain\Entity\AnalyticsEvent;
use Bot\Domain\Repository\AnalyticsRepositoryInterface;
use PDO;

final class DatabaseAnalyticsRepository implements AnalyticsRepositoryInterface
{
    public function __construct(
        private readonly PDO $pdo,
    ) {
    }

    public function save(AnalyticsEvent $event): void
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO analytics_events (type, user_id, media_id, payment_id, occurred_at)
             VALUES (:type, :user_id, :media_id, :payment_id, :occurred_at)'
        );
        $stmt->execute([
            'type' => $event->getType(),
            'user_id' => $event->getUserId(),
            'media_id' => $event->getMediaId(),
            'payment_id' => $event->getPaymentId(),
            'occurred_at' => $event->getOccurredAt()->format('Y-m-d H:i:s'),
        ]);
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function findByType(string $type): array
    {
        $stmt = $this->pdo->prepare('SELECT * FROM analytics_events WHERE type = :type ORDER BY occurred_at DESC');
        $stmt->execute(['type' => $type]);
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function findByMediaId(int $mediaId): array
    {
        $stmt = $this->pdo->prepare('SELECT * FROM analytics_events WHERE media_id = :media_id ORDER BY occurred_at DESC');
        $stmt->execute(['media_id' => $mediaId]);
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function findByUserId(int $userId): array
    {
        $stmt = $this->pdo->prepare('SELECT * FROM analytics_events WHERE user_id = :user_id ORDER BY occurred_at DESC');
        $stmt->execute(['user_id' => $userId]);
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function getAll(): array
    {
        $stmt = $this->pdo->query('SELECT * FROM analytics_events ORDER BY occurred_at DESC');
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function findByDateRange(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate): array
    {
        $stmt = $this->pdo->prepare(
            'SELECT * FROM analytics_events 
             WHERE occurred_at >= :start_date AND occurred_at <= :end_date 
             ORDER BY occurred_at DESC'
        );
        $stmt->execute([
            'start_date' => $startDate->format('Y-m-d H:i:s'),
            'end_date' => $endDate->format('Y-m-d H:i:s'),
        ]);
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @return AnalyticsEvent[]
     */
    public function findByUserIdAndDateRange(int $userId, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): array
    {
        $stmt = $this->pdo->prepare(
            'SELECT * FROM analytics_events 
             WHERE user_id = :user_id 
             AND occurred_at >= :start_date AND occurred_at <= :end_date 
             ORDER BY occurred_at DESC'
        );
        $stmt->execute([
            'user_id' => $userId,
            'start_date' => $startDate->format('Y-m-d H:i:s'),
            'end_date' => $endDate->format('Y-m-d H:i:s'),
        ]);
        $rows = $stmt->fetchAll();

        $events = [];
        foreach ($rows as $row) {
            $events[] = $this->rowToEvent($row);
        }

        return $events;
    }

    /**
     * @param array<string,mixed> $row
     */
    private function rowToEvent(array $row): AnalyticsEvent
    {
        return new AnalyticsEvent(
            (int) $row['id'],
            $row['type'],
            $row['user_id'] !== null ? (int) $row['user_id'] : null,
            $row['media_id'] !== null ? (int) $row['media_id'] : null,
            $row['payment_id'] !== null ? (int) $row['payment_id'] : null,
            new \DateTimeImmutable($row['occurred_at']),
        );
    }
}

