<?php

namespace App\Services;

use App\Models\CompetitorBrand;
use App\Models\CompetitorInsight;
use App\Models\CompetitorPost;
use App\Models\Brand;
use App\Models\SocialPost;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class CompetitorAnalysisService
{
    /**
     * Analyze competitor performance and generate insights.
     *
     * @param Brand $brand
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return CompetitorInsight
     */
    public function generateInsights(
        Brand $brand,
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): CompetitorInsight {
        // Create or get existing insight record
        $insight = CompetitorInsight::firstOrCreate(
            [
                'brand_id' => $brand->id,
                'competitor_brand_id' => $competitor->id,
                'start_date' => $startDate->toDateString(),
                'end_date' => $endDate->toDateString(),
            ],
            [
                'tenant_id' => $brand->tenant_id,
                'status' => 'pending',
            ]
        );

        $insight->markAsProcessing();

        try {
            // Gather competitor metrics
            $competitorMetrics = $this->gatherCompetitorMetrics($competitor, $startDate, $endDate);
            
            // Gather brand's own metrics for comparison
            $brandMetrics = $this->gatherBrandMetrics($brand, $startDate, $endDate);
            
            // Perform comparative analysis
            $comparisonData = $this->compareMetrics($competitorMetrics, $brandMetrics);
            
            // Analyze content strategy
            $contentStrategy = $this->analyzeContentStrategy($competitor, $startDate, $endDate);
            
            // Identify top performing posts
            $topPosts = $this->identifyTopPosts($competitor, $startDate, $endDate);
            
            // Analyze engagement patterns
            $engagementPatterns = $this->analyzeEngagementPatterns($competitor, $startDate, $endDate);
            
            // Analyze sentiment trends
            $sentimentTrends = $this->analyzeSentimentTrends($competitor, $startDate, $endDate);
            
            // Analyze topics
            $topics = $this->analyzeTopics($competitor, $startDate, $endDate);
            
            // Analyze hashtag performance
            $hashtagAnalysis = $this->analyzeHashtags($competitor, $startDate, $endDate);

            // Update insight with all data
            $insight->update([
                'competitor_metrics' => $competitorMetrics,
                'brand_metrics' => $brandMetrics,
                'comparison_data' => $comparisonData,
                'content_strategy' => $contentStrategy,
                'top_posts' => $topPosts,
                'engagement_patterns' => $engagementPatterns,
                'sentiment_trends' => $sentimentTrends,
                'topics' => $topics,
                'hashtag_analysis' => $hashtagAnalysis,
            ]);

            $insight->markAsCompleted();

            return $insight;
        } catch (\Exception $e) {
            Log::error("Failed to generate competitor insights: {$e->getMessage()}");
            $insight->markAsFailed($e->getMessage());
            throw $e;
        }
    }

    /**
     * Gather metrics for a competitor.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function gatherCompetitorMetrics(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->get();

        $totalPosts = $posts->count();
        $totalEngagement = $posts->sum(fn($post) => $post->getTotalEngagement());
        $totalViews = $posts->sum(fn($post) => $post->getViewsCount());
        $avgEngagementRate = $posts->avg('engagement_rate') ?? 0;

        return [
            'total_posts' => $totalPosts,
            'total_engagement' => $totalEngagement,
            'total_views' => $totalViews,
            'avg_engagement_rate' => round($avgEngagementRate, 2),
            'total_likes' => $posts->sum(fn($post) => $post->getLikesCount()),
            'total_comments' => $posts->sum(fn($post) => $post->getCommentsCount()),
            'total_shares' => $posts->sum(fn($post) => $post->getSharesCount()),
            'total_saves' => $posts->sum(fn($post) => $post->getSavesCount()),
            'posting_frequency' => $this->calculatePostingFrequency($posts, $startDate, $endDate),
        ];
    }

    /**
     * Gather metrics for the brand.
     *
     * @param Brand $brand
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function gatherBrandMetrics(Brand $brand, Carbon $startDate, Carbon $endDate): array
    {
        $posts = SocialPost::whereHas('socialAccount', function($query) use ($brand) {
            $query->where('brand_id', $brand->id);
        })
        ->whereBetween('published_at', [$startDate, $endDate])
        ->get();

        $totalPosts = $posts->count();
        $totalEngagement = $posts->sum(fn($post) => 
            $post->getLikesCount() + 
            $post->getCommentsCount() + 
            $post->getSharesCount() + 
            $post->getSavesCount()
        );
        $totalViews = $posts->sum(fn($post) => $post->getViewsCount());
        $avgEngagementRate = $posts->avg(fn($post) => $post->getEngagementRate()) ?? 0;

        return [
            'total_posts' => $totalPosts,
            'total_engagement' => $totalEngagement,
            'total_views' => $totalViews,
            'avg_engagement_rate' => round($avgEngagementRate, 2),
            'total_likes' => $posts->sum(fn($post) => $post->getLikesCount()),
            'total_comments' => $posts->sum(fn($post) => $post->getCommentsCount()),
            'total_shares' => $posts->sum(fn($post) => $post->getSharesCount()),
            'total_saves' => $posts->sum(fn($post) => $post->getSavesCount()),
            'posting_frequency' => $this->calculatePostingFrequency($posts, $startDate, $endDate),
        ];
    }

    /**
     * Compare competitor and brand metrics.
     *
     * @param array $competitorMetrics
     * @param array $brandMetrics
     * @return array
     */
    protected function compareMetrics(array $competitorMetrics, array $brandMetrics): array
    {
        $comparison = [];

        foreach ($competitorMetrics as $metric => $competitorValue) {
            $brandValue = $brandMetrics[$metric] ?? 0;
            
            $difference = $competitorValue - $brandValue;
            $percentageDiff = $brandValue > 0 
                ? round((($competitorValue - $brandValue) / $brandValue) * 100, 2)
                : 0;

            $comparison[$metric] = [
                'competitor' => $competitorValue,
                'brand' => $brandValue,
                'difference' => $difference,
                'difference_percentage' => $percentageDiff,
                'competitor_ahead' => $competitorValue > $brandValue,
            ];
        }

        return $comparison;
    }

    /**
     * Analyze content strategy.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function analyzeContentStrategy(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->get();

        // Analyze post types
        $postTypes = $posts->groupBy('post_type')->map->count();
        
        // Analyze platforms
        $platforms = $posts->groupBy('platform')->map->count();
        
        // Best performing post type
        $bestPostType = $posts->sortByDesc('engagement_rate')->first()?->post_type;

        return [
            'post_types' => $postTypes->toArray(),
            'platforms' => $platforms->toArray(),
            'best_performing_type' => $bestPostType,
            'content_mix' => $this->calculateContentMix($postTypes),
        ];
    }

    /**
     * Identify top performing posts.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @param int $limit
     * @return array
     */
    protected function identifyTopPosts(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate,
        int $limit = 10
    ): array {
        return $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->orderBy('engagement_rate', 'desc')
            ->limit($limit)
            ->get()
            ->map(function($post) {
                return [
                    'id' => $post->id,
                    'platform' => $post->platform,
                    'post_type' => $post->post_type,
                    'caption' => substr($post->caption ?? '', 0, 100),
                    'engagement_rate' => $post->engagement_rate,
                    'total_engagement' => $post->getTotalEngagement(),
                    'published_at' => $post->published_at->toDateTimeString(),
                    'permalink' => $post->permalink,
                ];
            })
            ->toArray();
    }

    /**
     * Analyze engagement patterns.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function analyzeEngagementPatterns(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->get();

        // Analyze posting times
        $postingByHour = $posts->groupBy(fn($post) => $post->published_at->hour);
        $postingByDay = $posts->groupBy(fn($post) => $post->published_at->dayOfWeek);

        // Find best performing times
        $bestHour = $postingByHour->map(fn($posts) => $posts->avg('engagement_rate'))
            ->sortDesc()
            ->keys()
            ->first();

        $bestDay = $postingByDay->map(fn($posts) => $posts->avg('engagement_rate'))
            ->sortDesc()
            ->keys()
            ->first();

        return [
            'posting_by_hour' => $postingByHour->map->count()->toArray(),
            'posting_by_day' => $postingByDay->map->count()->toArray(),
            'best_posting_hour' => $bestHour,
            'best_posting_day' => $bestDay,
            'avg_engagement_by_hour' => $postingByHour->map(fn($posts) => 
                round($posts->avg('engagement_rate'), 2)
            )->toArray(),
        ];
    }

    /**
     * Analyze sentiment trends.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function analyzeSentimentTrends(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->whereNotNull('sentiment')
            ->get();

        $sentimentCounts = $posts->groupBy('sentiment')->map->count();
        
        return [
            'sentiment_distribution' => $sentimentCounts->toArray(),
            'dominant_sentiment' => $sentimentCounts->sortDesc()->keys()->first(),
            'positive_percentage' => $posts->count() > 0 
                ? round(($sentimentCounts['positive'] ?? 0) / $posts->count() * 100, 2)
                : 0,
        ];
    }

    /**
     * Analyze topics.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function analyzeTopics(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->whereNotNull('topics')
            ->get();

        $allTopics = [];
        foreach ($posts as $post) {
            if (is_array($post->topics)) {
                $allTopics = array_merge($allTopics, $post->topics);
            }
        }

        $topicCounts = array_count_values($allTopics);
        arsort($topicCounts);

        return [
            'top_topics' => array_slice($topicCounts, 0, 10, true),
            'total_unique_topics' => count($topicCounts),
        ];
    }

    /**
     * Analyze hashtag performance.
     *
     * @param CompetitorBrand $competitor
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function analyzeHashtags(
        CompetitorBrand $competitor,
        Carbon $startDate,
        Carbon $endDate
    ): array {
        $posts = $competitor->posts()
            ->whereBetween('published_at', [$startDate, $endDate])
            ->whereNotNull('hashtags')
            ->get();

        $hashtagPerformance = [];
        
        foreach ($posts as $post) {
            if (is_array($post->hashtags)) {
                foreach ($post->hashtags as $hashtag) {
                    if (!isset($hashtagPerformance[$hashtag])) {
                        $hashtagPerformance[$hashtag] = [
                            'count' => 0,
                            'total_engagement' => 0,
                            'avg_engagement_rate' => 0,
                        ];
                    }
                    
                    $hashtagPerformance[$hashtag]['count']++;
                    $hashtagPerformance[$hashtag]['total_engagement'] += $post->getTotalEngagement();
                }
            }
        }

        // Calculate average engagement rate for each hashtag
        foreach ($hashtagPerformance as $hashtag => &$data) {
            $data['avg_engagement_rate'] = $data['count'] > 0 
                ? round($data['total_engagement'] / $data['count'], 2)
                : 0;
        }

        // Sort by average engagement rate
        uasort($hashtagPerformance, fn($a, $b) => $b['avg_engagement_rate'] <=> $a['avg_engagement_rate']);

        return [
            'top_hashtags' => array_slice($hashtagPerformance, 0, 20, true),
            'total_unique_hashtags' => count($hashtagPerformance),
        ];
    }

    /**
     * Calculate posting frequency.
     *
     * @param \Illuminate\Support\Collection $posts
     * @param Carbon $startDate
     * @param Carbon $endDate
     * @return array
     */
    protected function calculatePostingFrequency($posts, Carbon $startDate, Carbon $endDate): array
    {
        $days = $startDate->diffInDays($endDate) + 1;
        $postsPerDay = $posts->count() / $days;

        return [
            'posts_per_day' => round($postsPerDay, 2),
            'posts_per_week' => round($postsPerDay * 7, 2),
            'total_days' => $days,
        ];
    }

    /**
     * Calculate content mix percentages.
     *
     * @param \Illuminate\Support\Collection $postTypes
     * @return array
     */
    protected function calculateContentMix($postTypes): array
    {
        $total = $postTypes->sum();
        
        return $postTypes->map(function($count) use ($total) {
            return $total > 0 ? round(($count / $total) * 100, 2) : 0;
        })->toArray();
    }
}