<?php

declare(strict_types=1);

namespace App\Domain\SmartLink\Services;

use App\Domain\SmartLink\Repositories\ClickEventRepository;
use App\Domain\SmartLink\ValueObjects\SmartLinkId;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Click Statistics Aggregation Service
 *
 * Provides comprehensive analytics aggregations for SmartLink clicks including:
 * - Time-series click data
 * - Geographic distribution
 * - Device/Browser statistics
 * - Top-performing links
 * - Conversion metrics
 */
final readonly class ClickStatisticsService
{
    public function __construct(
        private ClickEventRepository $clickEventRepository
    ) {
    }

    /**
     * Get aggregated click statistics for a time period
     *
     * @return array{total_clicks: int, unique_clicks: int, conversions: int, conversion_rate: float}
     */
    public function getOverviewStats(?Timestamp $since = null): array
    {
        $totalClicks = $this->clickEventRepository->countTotal($since);
        $uniqueClicks = $this->clickEventRepository->countUniqueTotal($since);
        $conversions = $this->clickEventRepository->countConversionsTotal($since);

        $conversionRate = $totalClicks > 0
            ? ($conversions / $totalClicks) * 100
            : 0.0;

        return [
            'total_clicks' => $totalClicks,
            'unique_clicks' => $uniqueClicks,
            'conversions' => $conversions,
            'conversion_rate' => round($conversionRate, 2),
        ];
    }

    /**
     * Get click time-series data for chart visualization
     *
     * @param int $hours Number of hours to include (default: 24)
     * @return array<array{timestamp: string, clicks: int, unique_clicks: int}>
     */
    public function getClickTimeSeries(int $hours = 24): array
    {
        $since = Timestamp::now()->subtractHours($hours);
        $rawData = $this->clickEventRepository->getClickTimeSeriesByHour($since);

        // Transform for frontend consumption
        return array_map(function (array $row) {
            return [
                'timestamp' => $row['hour'],
                'clicks' => (int) $row['clicks'],
                'unique_clicks' => (int) $row['unique_clicks'],
            ];
        }, $rawData);
    }

    /**
     * Get geographic distribution of clicks
     *
     * @return array<array{country_code: string, country_name: string, click_count: int, percentage: float}>
     */
    public function getGeographicDistribution(?Timestamp $since = null): array
    {
        $rawData = $this->clickEventRepository->getGeographicDistribution($since);
        $totalClicks = array_sum(array_column($rawData, 'click_count'));

        return array_map(function (array $row) use ($totalClicks) {
            $percentage = $totalClicks > 0
                ? ((int) $row['click_count'] / $totalClicks) * 100
                : 0.0;

            return [
                'country_code' => $row['country_code'],
                'country_name' => $this->getCountryName($row['country_code']),
                'click_count' => (int) $row['click_count'],
                'percentage' => round($percentage, 2),
            ];
        }, $rawData);
    }

    /**
     * Get device type distribution
     *
     * @return array{mobile: int, desktop: int, tablet: int, mobile_percentage: float, desktop_percentage: float, tablet_percentage: float}
     */
    public function getDeviceDistribution(?Timestamp $since = null): array
    {
        $rawData = $this->clickEventRepository->getDeviceTypeDistribution($since);

        $mobile = 0;
        $desktop = 0;
        $tablet = 0;

        foreach ($rawData as $row) {
            $count = (int) $row['click_count'];
            match ($row['device_type']) {
                'mobile' => $mobile = $count,
                'desktop' => $desktop = $count,
                'tablet' => $tablet = $count,
                default => null,
            };
        }

        $total = $mobile + $desktop + $tablet;

        return [
            'mobile' => $mobile,
            'desktop' => $desktop,
            'tablet' => $tablet,
            'mobile_percentage' => $total > 0 ? round(($mobile / $total) * 100, 2) : 0.0,
            'desktop_percentage' => $total > 0 ? round(($desktop / $total) * 100, 2) : 0.0,
            'tablet_percentage' => $total > 0 ? round(($tablet / $total) * 100, 2) : 0.0,
        ];
    }

    /**
     * Get top performing links by click count
     *
     * @param int $limit Number of links to return (default: 10)
     * @return array<array{link_id: string, clicks: int, unique_clicks: int}>
     */
    public function getTopPerformingLinks(int $limit = 10, ?Timestamp $since = null): array
    {
        $rawData = $this->clickEventRepository->getTopLinksByClicks($limit, $since);

        // Note: For now, we return the aggregated data without joining to smart_links table
        // Frontend will need to fetch link details separately or we can implement a JOIN query
        return array_map(function (array $row) {
            return [
                'link_id' => $row['link_id'],
                'clicks' => (int) $row['click_count'],
                'unique_clicks' => (int) $row['unique_click_count'],
            ];
        }, $rawData);
    }

    /**
     * Get browser distribution statistics
     *
     * @return array<array{browser: string, click_count: int, percentage: float}>
     */
    public function getBrowserDistribution(?Timestamp $since = null): array
    {
        // TODO: Implement browser parsing from user_agent field
        // This requires user-agent parsing library or regex patterns
        return [];
    }

    /**
     * Get real-time click statistics (last 60 minutes)
     *
     * @return array{last_minute: int, last_5_minutes: int, last_15_minutes: int, last_60_minutes: int}
     */
    public function getRealTimeStats(): array
    {
        $now = Timestamp::now();

        return [
            'last_minute' => $this->clickEventRepository->countTotal($now->subtractMinutes(1)),
            'last_5_minutes' => $this->clickEventRepository->countTotal($now->subtractMinutes(5)),
            'last_15_minutes' => $this->clickEventRepository->countTotal($now->subtractMinutes(15)),
            'last_60_minutes' => $this->clickEventRepository->countTotal($now->subtractMinutes(60)),
        ];
    }

    /**
     * Helper: Get country name from country code
     */
    private function getCountryName(string $countryCode): string
    {
        // Simple country code mapping - could be replaced with a proper library
        $countries = [
            'DE' => 'Germany',
            'US' => 'United States',
            'GB' => 'United Kingdom',
            'FR' => 'France',
            'ES' => 'Spain',
            'IT' => 'Italy',
            'NL' => 'Netherlands',
            'AT' => 'Austria',
            'CH' => 'Switzerland',
            'BE' => 'Belgium',
        ];

        return $countries[$countryCode] ?? $countryCode;
    }

    /**
     * Get click statistics for a specific link
     *
     * @return array{total_clicks: int, unique_clicks: int, conversions: int, conversion_rate: float, avg_clicks_per_day: float}
     */
    public function getLinkStatistics(SmartLinkId $linkId, ?Timestamp $since = null): array
    {
        $totalClicks = $this->clickEventRepository->countByLinkId($linkId);
        $uniqueClicks = $this->clickEventRepository->countUniqueByLinkId($linkId);
        $conversions = $this->clickEventRepository->getConversionsByLinkId($linkId);

        $conversionRate = $totalClicks > 0
            ? ($conversions / $totalClicks) * 100
            : 0.0;

        // Calculate average clicks per day
        $daysSince = $since ? $since->diffInDays(Timestamp::now()) : 30; // Default 30 days
        $avgClicksPerDay = $daysSince > 0
            ? $totalClicks / $daysSince
            : 0.0;

        return [
            'total_clicks' => $totalClicks,
            'unique_clicks' => $uniqueClicks,
            'conversions' => $conversions,
            'conversion_rate' => round($conversionRate, 2),
            'avg_clicks_per_day' => round($avgClicksPerDay, 2),
        ];
    }
}
