<?php

namespace App\Services;

use App\Models\Notification;
use App\Models\UserNotificationPreference;
use App\Models\NotificationDelivery;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;

class NotificationService
{
    /**
     * Create a new notification draft.
     */
    public function createNotification(array $data): Notification
    {
        return Notification::create([
            'title' => $data['title'],
            'message' => $data['message'],
            'deep_link_url' => $data['deep_link_url'] ?? null,
            'target_type' => $data['target_type'],
            'target_value' => $data['target_value'] ?? null,
            'scheduled_at' => $data['scheduled_at'] ?? null,
            'status' => 'draft',
            'ab_test_enabled' => $data['ab_test_enabled'] ?? false,
            'ab_test_variants' => $data['ab_test_variants'] ?? null,
            'priority' => $data['priority'] ?? 'normal',
            'category' => $data['category'] ?? 'general',
            'image' => $data['image'] ?? null
        ]);
    }

    /**
     * Create A/B test variants for a notification.
     */
    public function createABTestVariants(Notification $notification, array $variants): bool
    {
        if (!$notification->ab_test_enabled || count($variants) < 2) {
            return false;
        }

        DB::transaction(function () use ($notification, $variants) {
            foreach ($variants as $variant) {
                Notification::create([
                    'title' => $variant['title'],
                    'message' => $variant['message'],
                    'deep_link_url' => $variant['deep_link_url'] ?? $notification->deep_link_url,
                    'target_type' => $notification->target_type,
                    'target_value' => $notification->target_value,
                    'scheduled_at' => $notification->scheduled_at,
                    'status' => 'draft',
                    'parent_notification_id' => $notification->id,
                    'ab_test_variant' => $variant['name'],
                    'ab_test_group' => $variant['group'],
                    'priority' => $notification->priority,
                    'category' => $notification->category
                ]);
            }
        });

        return true;
    }

    /**
     * Get best performing A/B test variant.
     */
    public function getBestABVariant(Notification $parentNotification): ?Notification
    {
        return $parentNotification->abTestVariants()
            ->where('status', 'sent')
            ->orderByRaw('(clicked_count * 1.0 / delivered_count) DESC')
            ->first();
    }

    /**
     * Schedule a notification for sending.
     */
    public function scheduleNotification(Notification $notification, ?\DateTime $scheduledAt = null): bool
    {
        return $notification->update([
            'scheduled_at' => $scheduledAt,
            'status' => 'scheduled'
        ]);
    }

    /**
     * Send a notification immediately.
     */
    public function sendNotification(Notification $notification): bool
    {
        if (!$notification->isReadyToSend()) {
            return false;
        }

        $notification->update(['status' => 'sending']);

        try {
            $targetUsers = $this->getTargetUsers($notification);
            $this->sendToUsers($notification, $targetUsers);
            
            $notification->update([
                'status' => 'sent',
                'sent_at' => now()
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Notification sending failed: ' . $e->getMessage());
            $notification->update(['status' => 'failed']);
            return false;
        }
    }

    /**
     * Get users who should receive this notification.
     */
    protected function getTargetUsers(Notification $notification): \Illuminate\Database\Eloquent\Collection
    {
        switch ($notification->target_type) {
            case 'all':
                return $this->getAllUsers($notification);
            case 'single_user':
                return $this->getSingleUsers($notification);
            case 'premium_plan':
                return $this->getPremiumPlanUsers($notification);
            case 'custom':
                return $this->getCustomTargetUsers($notification);
            default:
                return collect();
        }
    }

    /**
     * Get all active users, optionally filtered by location.
     */
    protected function getAllUsers(?Notification $notification = null): \Illuminate\Database\Eloquent\Collection
    {
        $query = User::whereHas('notificationPreference', function ($query) {
                $query->where('enabled', true);
            })
            ->with('notificationPreference');
        
        if ($notification) {
            $this->applyLocationFilters($query, $notification->target_value);
        }

        return $query->get();
    }

    /**
     * Get specific users by ID.
     */
    protected function getSingleUsers(Notification $notification): \Illuminate\Database\Eloquent\Collection
    {
        $userIds = $notification->target_value['user_ids'] ?? [];
        
        return User::whereIn('id', $userIds)
            ->whereHas('notificationPreference', function ($query) {
                $query->where('enabled', true);
            })
            ->with('notificationPreference')
            ->get();
    }

    /**
     * Get users with specific premium plans, optionally filtered by location.
     */
    protected function getPremiumPlanUsers(Notification $notification): \Illuminate\Database\Eloquent\Collection
    {
        $planTypes = $notification->target_value['plan_types'] ?? [];
        
        $query = User::whereHas('notificationPreference', function ($query) {
                $query->where('enabled', true);
            })
            ->with(['notificationPreference', 'subscriptions' => function ($query) {
                $query->where('status', 'active');
            }]);

        if (in_array('standard', $planTypes)) {
            // Include users without active subscriptions (Standard/Free users)
            $query->whereDoesntHave('subscriptions', function ($query) {
                $query->where('status', 'active');
            });
        }

        // Filter valid plan names (exclude 'standard' from this check as it's handled above)
        $paidPlanTypes = array_diff($planTypes, ['standard']);

        if (count($paidPlanTypes) > 0) {
            $query->whereHas('subscriptions', function ($query) use ($paidPlanTypes) {
                $query->where('status', 'active')
                      ->whereHas('plan', function ($q) use ($paidPlanTypes) {
                          $q->whereIn('plan_name', $paidPlanTypes);
                      });
            });
        }

        $this->applyLocationFilters($query, $notification->target_value);

        return $query->get();
    }

    /**
     * Get users based on custom targeting rules (including Location).
     */
    protected function getCustomTargetUsers(Notification $notification): \Illuminate\Database\Eloquent\Collection
    {
        $query = User::whereHas('notificationPreference', function ($query) {
                $query->where('enabled', true);
            })
            ->with('notificationPreference');

        $this->applyLocationFilters($query, $notification->target_value);
        
        // If there are specific targeting rules, filter them in memory for now
        // or we could implement them in the query.
        $users = $query->get();

        if ($notification->targetingRules && $notification->targetingRules->count() > 0) {
            return $users->filter(function ($user) use ($notification) {
                return $notification->targetingRules->every(function ($rule) use ($user) {
                    return $rule->matchesUser($user);
                });
            });
        }

        return $users;
    }

    /**
     * Apply location filters to the user query.
     */
    protected function applyLocationFilters($query, $targetValue)
    {
        if (empty($targetValue)) return;

        if (!empty($targetValue['city'])) {
            $query->where('city', 'like', '%' . $targetValue['city'] . '%');
        }

        if (!empty($targetValue['state'])) {
            $query->where('state', 'like', '%' . $targetValue['state'] . '%');
        }

        if (!empty($targetValue['country'])) {
            $query->where('country', 'like', '%' . $targetValue['country'] . '%');
        }
    }

    /**
     * Send notification to multiple users.
     */
    protected function sendToUsers(Notification $notification, \Illuminate\Database\Eloquent\Collection $users): void
    {
        foreach ($users as $user) {
            $this->sendToUser($notification, $user);
        }
    }

    /**
     * Send notification to a single user.
     */
    protected function sendToUser(Notification $notification, User $user): void
    {
        // Check user preferences
        $preference = $user->notificationPreference;
        if (!$preference || !$preference->shouldReceiveNotification('general')) {
            return;
        }

        // Create delivery record
        $delivery = NotificationDelivery::create([
            'notification_id' => $notification->id,
            'user_id' => $user->id,
            'status' => 'pending'
        ]);

        // Send via Firebase
        $firebaseService = app(FirebaseService::class);
        $deviceToken = $user->device_token; // Assuming you store device tokens on users

        if ($deviceToken && $firebaseService->sendPushNotification($user, $notification, $delivery)) {
            $delivery->markAsDelivered($deviceToken);
        } else {
            $delivery->markAsFailed('No device token or Firebase send failed');
        }
    }

    /**
     * Get notification statistics.
     */
    public function getNotificationStats(Notification $notification): array
    {
        $totalDeliveries = $notification->deliveries()->count();
        $deliveredCount = $notification->deliveries()->where('status', 'delivered')->count();
        $openedCount = $notification->deliveries()->where('status', 'opened')->count();
        $clickedCount = $notification->deliveries()->where('status', 'clicked')->count();

        $deliveryRate = $totalDeliveries > 0 ? ($deliveredCount / $totalDeliveries) * 100 : 0;
        $openRate = $deliveredCount > 0 ? ($openedCount / $deliveredCount) * 100 : 0;
        $clickRate = $deliveredCount > 0 ? ($clickedCount / $deliveredCount) * 100 : 0;

        return [
            'total_deliveries' => $totalDeliveries,
            'delivered' => $deliveredCount,
            'opened' => $openedCount,
            'clicked' => $clickedCount,
            'delivery_rate' => round($deliveryRate, 2),
            'open_rate' => round($openRate, 2),
            'click_rate' => round($clickRate, 2),
        ];
    }

    /**
     * Get user's notification history.
     */
    public function getUserNotifications(User $user, int $limit = 50): \Illuminate\Database\Eloquent\Collection
    {
        return Notification::whereHas('deliveries', function ($query) use ($user) {
            $query->where('user_id', $user->id);
        })
        ->with(['deliveries' => function ($query) use ($user) {
            $query->where('user_id', $user->id);
        }])
        ->orderBy('sent_at', 'desc')
        ->limit($limit)
        ->get();
    }

    /**
     * Mark notification as opened by user.
     */
    public function markAsOpened(User $user, Notification $notification): bool
    {
        $delivery = $notification->deliveries()->where('user_id', $user->id)->first();
        
        if ($delivery) {
            return $delivery->markAsOpened();
        }

        return false;
    }

    /**
     * Mark notification as clicked by user.
     */
    public function markAsClicked(User $user, Notification $notification): bool
    {
        $delivery = $notification->deliveries()->where('user_id', $user->id)->first();
        
        if ($delivery) {
            return $delivery->markAsClicked();
        }

        return false;
    }
}
