<?php

namespace App\Services;

use App\Models\Brand;
use App\Models\Campaign;
use App\Models\PerformanceForecast;
use App\Models\SocialAccount;
use App\Models\SocialPost;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class PerformanceForecastService
{
    /**
     * Generate a performance forecast for campaigns or social accounts.
     *
     * @param Brand $brand
     * @param array $params
     * @return PerformanceForecast
     */
    public function generateForecast(Brand $brand, array $params)
    {
        // Create the forecast record
        $forecast = PerformanceForecast::create([
            'brand_id' => $brand->id,
            'created_by' => auth()->id(),
            'campaign_ids' => $params['campaign_ids'] ?? null,
            'social_account_ids' => $params['social_account_ids'] ?? null,
            'start_date' => $params['start_date'],
            'end_date' => $params['end_date'],
            'forecast_days' => $params['forecast_days'] ?? 30,
            'scenario' => $params['scenario'] ?? 'balanced',
            'input_metrics' => [],
            'status' => 'pending',
        ]);

        return $forecast;
    }

    /**
     * Process the forecast by gathering historical data and generating predictions.
     *
     * @param PerformanceForecast $forecast
     * @return void
     */
    public function processForecast(PerformanceForecast $forecast)
    {
        try {
            $forecast->markAsProcessing();

            // Gather historical metrics
            $historicalMetrics = $this->gatherHistoricalMetrics($forecast);

            // Update input metrics
            $forecast->update(['input_metrics' => $historicalMetrics]);

            // Generate predictions using AI
            $predictions = $this->generatePredictions($forecast, $historicalMetrics);

            // Mark as completed with results
            $forecast->markAsCompleted($predictions);

            Log::info('Forecast completed successfully', ['forecast_id' => $forecast->id]);
        } catch (\Exception $e) {
            $forecast->markAsFailed($e->getMessage());
            Log::error('Forecast processing failed', [
                'forecast_id' => $forecast->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Gather historical metrics from campaigns or social accounts.
     *
     * @param PerformanceForecast $forecast
     * @return array
     */
    protected function gatherHistoricalMetrics(PerformanceForecast $forecast)
    {
        $metrics = [
            'impressions' => [],
            'clicks' => [],
            'conversions' => [],
            'engagement' => [],
            'reach' => [],
            'dates' => [],
        ];

        // Build query for social posts
        $postsQuery = SocialPost::query()
            ->where('published_at', '>=', $forecast->start_date)
            ->where('published_at', '<=', $forecast->end_date);

        // Filter by campaigns if specified
        if (!empty($forecast->campaign_ids)) {
            $postsQuery->whereIn('campaign_id', $forecast->campaign_ids);
        }

        // Filter by social accounts if specified
        if (!empty($forecast->social_account_ids)) {
            $postsQuery->whereIn('social_account_id', $forecast->social_account_ids);
        } else {
            // Filter by brand's social accounts
            $postsQuery->whereHas('socialAccount', function ($query) use ($forecast) {
                $query->where('brand_id', $forecast->brand_id);
            });
        }

        // Get posts grouped by date
        $posts = $postsQuery->orderBy('published_at')->get();

        // Aggregate metrics by date
        $dailyMetrics = [];
        foreach ($posts as $post) {
            $date = $post->published_at->format('Y-m-d');
            $postMetrics = $post->metrics ?? [];

            if (!isset($dailyMetrics[$date])) {
                $dailyMetrics[$date] = [
                    'impressions' => 0,
                    'clicks' => 0,
                    'conversions' => 0,
                    'engagement' => 0,
                    'reach' => 0,
                ];
            }

            $dailyMetrics[$date]['impressions'] += $postMetrics['views'] ?? 0;
            $dailyMetrics[$date]['clicks'] += $postMetrics['clicks'] ?? 0;
            $dailyMetrics[$date]['conversions'] += $postMetrics['conversions'] ?? 0;
            $dailyMetrics[$date]['engagement'] += ($postMetrics['likes'] ?? 0) + 
                                                   ($postMetrics['comments'] ?? 0) + 
                                                   ($postMetrics['shares'] ?? 0);
            $dailyMetrics[$date]['reach'] += $postMetrics['reach'] ?? $postMetrics['views'] ?? 0;
        }

        // Convert to arrays for time series
        foreach ($dailyMetrics as $date => $values) {
            $metrics['dates'][] = $date;
            $metrics['impressions'][] = $values['impressions'];
            $metrics['clicks'][] = $values['clicks'];
            $metrics['conversions'][] = $values['conversions'];
            $metrics['engagement'][] = $values['engagement'];
            $metrics['reach'][] = $values['reach'];
        }

        return $metrics;
    }

    /**
     * Generate predictions using AI/statistical models.
     *
     * @param PerformanceForecast $forecast
     * @param array $historicalMetrics
     * @return array
     */
    protected function generatePredictions(PerformanceForecast $forecast, array $historicalMetrics)
    {
        // Apply scenario multipliers
        $multipliers = $this->getScenarioMultipliers($forecast->scenario);

        // Calculate baseline trends
        $trends = $this->calculateTrends($historicalMetrics);

        // Generate time series predictions
        $predictedTimeseries = $this->generateTimeSeriesPredictions(
            $historicalMetrics,
            $forecast->forecast_days,
            $trends,
            $multipliers
        );

        // Calculate error bands (95% confidence intervals)
        $errorBands = $this->calculateErrorBands($predictedTimeseries, $historicalMetrics);

        // Estimate ROI
        $roiEstimates = $this->estimateROI($predictedTimeseries, $forecast);

        // Generate AI insights
        $insights = $this->generateInsights($predictedTimeseries, $roiEstimates, $forecast);

        return [
            'predicted_timeseries' => $predictedTimeseries,
            'error_bands' => $errorBands,
            'roi_estimates' => $roiEstimates,
            'insights_text' => $insights['text'],
            'insights_meta' => $insights['meta'],
        ];
    }

    /**
     * Get scenario multipliers for predictions.
     *
     * @param string $scenario
     * @return array
     */
    protected function getScenarioMultipliers(string $scenario)
    {
        return match ($scenario) {
            'conservative' => [
                'growth_rate' => 0.95,
                'volatility' => 0.8,
            ],
            'aggressive' => [
                'growth_rate' => 1.15,
                'volatility' => 1.3,
            ],
            default => [ // balanced
                'growth_rate' => 1.05,
                'volatility' => 1.0,
            ],
        };
    }

    /**
     * Calculate trends from historical data.
     *
     * @param array $historicalMetrics
     * @return array
     */
    protected function calculateTrends(array $historicalMetrics)
    {
        $trends = [];

        foreach (['impressions', 'clicks', 'conversions', 'engagement', 'reach'] as $metric) {
            $values = $historicalMetrics[$metric] ?? [];
            
            if (empty($values)) {
                $trends[$metric] = 0;
                continue;
            }

            // Simple linear regression for trend
            $n = count($values);
            $sumX = array_sum(range(0, $n - 1));
            $sumY = array_sum($values);
            $sumXY = 0;
            $sumX2 = 0;

            for ($i = 0; $i < $n; $i++) {
                $sumXY += $i * $values[$i];
                $sumX2 += $i * $i;
            }

            $slope = ($n * $sumXY - $sumX * $sumY) / ($n * $sumX2 - $sumX * $sumX);
            $trends[$metric] = $slope;
        }

        return $trends;
    }

    /**
     * Generate time series predictions.
     *
     * @param array $historicalMetrics
     * @param int $forecastDays
     * @param array $trends
     * @param array $multipliers
     * @return array
     */
    protected function generateTimeSeriesPredictions(
        array $historicalMetrics,
        int $forecastDays,
        array $trends,
        array $multipliers
    ) {
        $predictions = [
            'dates' => [],
            'impressions' => [],
            'clicks' => [],
            'conversions' => [],
            'engagement' => [],
            'reach' => [],
        ];

        // Get last known values
        $lastValues = [];
        foreach (['impressions', 'clicks', 'conversions', 'engagement', 'reach'] as $metric) {
            $values = $historicalMetrics[$metric] ?? [];
            $lastValues[$metric] = !empty($values) ? end($values) : 0;
        }

        // Generate predictions for each day
        $startDate = now();
        for ($day = 1; $day <= $forecastDays; $day++) {
            $date = $startDate->copy()->addDays($day)->format('Y-m-d');
            $predictions['dates'][] = $date;

            foreach (['impressions', 'clicks', 'conversions', 'engagement', 'reach'] as $metric) {
                $trend = $trends[$metric] ?? 0;
                $lastValue = $lastValues[$metric];
                
                // Apply trend and growth multiplier
                $predicted = $lastValue + ($trend * $day * $multipliers['growth_rate']);
                
                // Ensure non-negative
                $predicted = max(0, $predicted);
                
                $predictions[$metric][] = round($predicted);
                $lastValues[$metric] = $predicted;
            }
        }

        return $predictions;
    }

    /**
     * Calculate error bands (confidence intervals).
     *
     * @param array $predictions
     * @param array $historicalMetrics
     * @return array
     */
    protected function calculateErrorBands(array $predictions, array $historicalMetrics)
    {
        $errorBands = [];

        foreach (['impressions', 'clicks', 'conversions', 'engagement', 'reach'] as $metric) {
            $historicalValues = $historicalMetrics[$metric] ?? [];
            
            if (empty($historicalValues)) {
                $errorBands[$metric] = ['lower' => [], 'upper' => []];
                continue;
            }

            // Calculate standard deviation
            $mean = array_sum($historicalValues) / count($historicalValues);
            $variance = 0;
            foreach ($historicalValues as $value) {
                $variance += pow($value - $mean, 2);
            }
            $stdDev = sqrt($variance / count($historicalValues));

            // 95% confidence interval (±1.96 * stdDev)
            $errorMargin = 1.96 * $stdDev;

            $errorBands[$metric] = [
                'lower' => array_map(fn($v) => max(0, $v - $errorMargin), $predictions[$metric]),
                'upper' => array_map(fn($v) => $v + $errorMargin, $predictions[$metric]),
            ];
        }

        return $errorBands;
    }

    /**
     * Estimate ROI from predictions.
     *
     * @param array $predictions
     * @param PerformanceForecast $forecast
     * @return array
     */
    protected function estimateROI(array $predictions, PerformanceForecast $forecast)
    {
        $totalImpressions = array_sum($predictions['impressions'] ?? []);
        $totalClicks = array_sum($predictions['clicks'] ?? []);
        $totalConversions = array_sum($predictions['conversions'] ?? []);
        $totalEngagement = array_sum($predictions['engagement'] ?? []);
        $totalReach = array_sum($predictions['reach'] ?? []);

        // Calculate engagement rate
        $engagementRate = $totalImpressions > 0 
            ? round(($totalEngagement / $totalImpressions) * 100, 2) 
            : 0;

        // Calculate CTR
        $ctr = $totalImpressions > 0 
            ? round(($totalClicks / $totalImpressions) * 100, 2) 
            : 0;

        // Calculate conversion rate
        $conversionRate = $totalClicks > 0 
            ? round(($totalConversions / $totalClicks) * 100, 2) 
            : 0;

        // Estimate ROI (simplified calculation)
        // Assuming average conversion value and campaign budget
        $avgConversionValue = 50; // This should come from campaign data
        $estimatedRevenue = $totalConversions * $avgConversionValue;
        
        $campaignBudget = 0;
        if (!empty($forecast->campaign_ids)) {
            $campaignBudget = Campaign::whereIn('id', $forecast->campaign_ids)
                ->sum('budget');
        }

        $roi = $campaignBudget > 0 
            ? round((($estimatedRevenue - $campaignBudget) / $campaignBudget) * 100, 2) 
            : 0;

        return [
            'roi' => $roi,
            'reach' => $totalReach,
            'conversions' => $totalConversions,
            'engagement_rate' => $engagementRate,
            'ctr' => $ctr,
            'conversion_rate' => $conversionRate,
            'estimated_revenue' => $estimatedRevenue,
            'total_impressions' => $totalImpressions,
            'total_clicks' => $totalClicks,
            'total_engagement' => $totalEngagement,
        ];
    }

    /**
     * Generate actionable insights from predictions.
     *
     * @param array $predictions
     * @param array $roiEstimates
     * @param PerformanceForecast $forecast
     * @return array
     */
    protected function generateInsights(array $predictions, array $roiEstimates, PerformanceForecast $forecast)
    {
        $insights = [];
        $insightText = [];

        // ROI insight
        if ($roiEstimates['roi'] > 0) {
            $insights[] = [
                'type' => 'positive',
                'title' => 'Positive ROI Expected',
                'description' => "Forecast shows a {$roiEstimates['roi']}% ROI over the next {$forecast->forecast_days} days.",
                'action' => 'Continue current strategy',
            ];
            $insightText[] = "Expected ROI of {$roiEstimates['roi']}% indicates strong campaign performance.";
        } else {
            $insights[] = [
                'type' => 'warning',
                'title' => 'ROI Optimization Needed',
                'description' => 'Current trajectory shows negative ROI.',
                'action' => 'Consider adjusting targeting or creative strategy',
            ];
            $insightText[] = "ROI optimization recommended to improve campaign profitability.";
        }

        // Engagement rate insight
        if ($roiEstimates['engagement_rate'] < 2) {
            $insights[] = [
                'type' => 'recommendation',
                'title' => 'Boost Engagement',
                'description' => "Engagement rate of {$roiEstimates['engagement_rate']}% is below industry average.",
                'action' => 'Shift budget to reels and interactive content for +10% engagement boost',
            ];
            $insightText[] = "Shift budget to reels for +10% engagement boost.";
        }

        // Conversion rate insight
        if ($roiEstimates['conversion_rate'] > 0 && $roiEstimates['conversion_rate'] < 1) {
            $insights[] = [
                'type' => 'recommendation',
                'title' => 'Improve Conversion Funnel',
                'description' => "Conversion rate of {$roiEstimates['conversion_rate']}% suggests funnel optimization opportunities.",
                'action' => 'Review landing pages and call-to-action effectiveness',
            ];
            $insightText[] = "Optimize conversion funnel to improve {$roiEstimates['conversion_rate']}% conversion rate.";
        }

        // Reach insight
        $avgDailyReach = $roiEstimates['reach'] / $forecast->forecast_days;
        if ($avgDailyReach > 10000) {
            $insights[] = [
                'type' => 'positive',
                'title' => 'Strong Reach Performance',
                'description' => "Average daily reach of " . number_format($avgDailyReach) . " shows good audience penetration.",
                'action' => 'Maintain current distribution strategy',
            ];
        }

        return [
            'text' => implode(' ', $insightText),
            'meta' => [
                'actionable_insights' => $insights,
                'scenario' => $forecast->scenario,
                'confidence_level' => 0.95,
            ],
        ];
    }

    /**
     * Compare different forecast scenarios.
     *
     * @param Brand $brand
     * @param array $params
     * @return array
     */
    public function compareScenarios(Brand $brand, array $params)
    {
        $scenarios = ['conservative', 'balanced', 'aggressive'];
        $comparisons = [];

        foreach ($scenarios as $scenario) {
            $scenarioParams = array_merge($params, ['scenario' => $scenario]);
            $forecast = $this->generateForecast($brand, $scenarioParams);
            $this->processForecast($forecast);
            
            $comparisons[$scenario] = [
                'forecast_id' => $forecast->id,
                'roi' => $forecast->roi_estimates['roi'] ?? 0,
                'reach' => $forecast->roi_estimates['reach'] ?? 0,
                'conversions' => $forecast->roi_estimates['conversions'] ?? 0,
                'engagement_rate' => $forecast->roi_estimates['engagement_rate'] ?? 0,
            ];
        }

        return $comparisons;
    }
}