<?php

declare(strict_types=1);

namespace Bot\Domain\Service;

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

final class AnalyticsService
{
    public function __construct(
        private readonly AnalyticsRepositoryInterface $analyticsRepository,
    ) {
    }

    public function recordDownload(?int $userId, ?int $mediaId): void
    {
        $this->storeEvent('download', $userId, $mediaId, null);
    }

    public function recordClick(?int $userId, ?int $mediaId): void
    {
        $this->storeEvent('click', $userId, $mediaId, null);
    }

    public function recordJoinConverted(?int $userId): void
    {
        $this->storeEvent('join_converted', $userId, null, null);
    }

    public function recordPayment(?int $userId, ?int $paymentId): void
    {
        $this->storeEvent('payment', $userId, null, $paymentId);
    }

    public function getDownloadCount(?int $mediaId = null): int
    {
        $events = $mediaId !== null
            ? $this->analyticsRepository->findByMediaId($mediaId)
            : $this->analyticsRepository->findByType('download');
        return count(array_filter($events, fn($e) => $e->getType() === 'download'));
    }

    public function getClickCount(?int $mediaId = null): int
    {
        $events = $mediaId !== null
            ? $this->analyticsRepository->findByMediaId($mediaId)
            : $this->analyticsRepository->findByType('click');
        return count(array_filter($events, fn($e) => $e->getType() === 'click'));
    }

    public function getJoinConvertedCount(): int
    {
        return count($this->analyticsRepository->findByType('join_converted'));
    }

    public function getRevenueByGateway(string $gateway): int
    {
        $allEvents = $this->analyticsRepository->getAll();
        $paymentEvents = array_filter($allEvents, fn($e) => $e->getType() === 'payment');
        // در یک پیاده‌سازی واقعی، باید payment را از paymentId پیدا کنیم و gateway را بررسی کنیم
        // برای سادگی، فقط تعداد پرداخت‌ها را برمی‌گردانیم
        return count($paymentEvents);
    }

    public function getTotalRevenue(): int
    {
        return count($this->analyticsRepository->findByType('payment'));
    }

    public function getConversionRate(): float
    {
        $totalClicks = $this->getClickCount();
        $totalDownloads = $this->getDownloadCount();
        if ($totalClicks === 0) {
            return 0.0;
        }
        return ($totalDownloads / $totalClicks) * 100;
    }

    /**
     * دریافت تعداد دانلودهای یک کاربر خاص
     */
    public function getDownloadCountForUser(int $userId): int
    {
        $events = $this->analyticsRepository->findByUserId($userId);
        return count(array_filter($events, fn($e) => $e->getType() === 'download'));
    }

    /**
     * دریافت تعداد کلیک‌های یک کاربر خاص
     */
    public function getClickCountForUser(int $userId): int
    {
        $events = $this->analyticsRepository->findByUserId($userId);
        return count(array_filter($events, fn($e) => $e->getType() === 'click'));
    }

    /**
     * دریافت تعداد پرداخت‌های موفق یک کاربر خاص
     */
    public function getPaymentCountForUser(int $userId): int
    {
        $events = $this->analyticsRepository->findByUserId($userId);
        return count(array_filter($events, fn($e) => $e->getType() === 'payment'));
    }

    /**
     * دریافت تعداد دانلودهای یک کاربر در بازه زمانی مشخص
     */
    public function getDownloadCountForUserInRange(int $userId, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
    {
        $events = $this->analyticsRepository->findByUserIdAndDateRange($userId, $startDate, $endDate);
        return count(array_filter($events, fn($e) => $e->getType() === 'download'));
    }

    /**
     * دریافت تعداد کلیک‌های یک کاربر در بازه زمانی مشخص
     */
    public function getClickCountForUserInRange(int $userId, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
    {
        $events = $this->analyticsRepository->findByUserIdAndDateRange($userId, $startDate, $endDate);
        return count(array_filter($events, fn($e) => $e->getType() === 'click'));
    }

    /**
     * دریافت تعداد پرداخت‌های یک کاربر در بازه زمانی مشخص
     */
    public function getPaymentCountForUserInRange(int $userId, \DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
    {
        $events = $this->analyticsRepository->findByUserIdAndDateRange($userId, $startDate, $endDate);
        return count(array_filter($events, fn($e) => $e->getType() === 'payment'));
    }

    /**
     * دریافت تعداد کل کاربران در بازه زمانی مشخص (کاربران منحصر به فرد)
     */
    public function getUniqueUsersCountInRange(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate): int
    {
        $events = $this->analyticsRepository->findByDateRange($startDate, $endDate);
        $userIds = array_filter(
            array_map(fn($e) => $e->getUserId(), $events),
            fn($id) => $id !== null
        );
        return count(array_unique($userIds));
    }

    /**
     * دریافت تعداد کل کاربران (کاربران منحصر به فرد)
     */
    public function getTotalUniqueUsersCount(): int
    {
        $events = $this->analyticsRepository->getAll();
        $userIds = array_filter(
            array_map(fn($e) => $e->getUserId(), $events),
            fn($id) => $id !== null
        );
        return count(array_unique($userIds));
    }

    private function storeEvent(
        string $type,
        ?int $userId,
        ?int $mediaId,
        ?int $paymentId,
    ): void {
        // In a real implementation, id would be generated by persistence layer.
        $event = new AnalyticsEvent(
            0,
            $type,
            $userId,
            $mediaId,
            $paymentId,
            new \DateTimeImmutable(),
        );

        $this->analyticsRepository->save($event);
    }
}



