<?php

namespace App\Services;

use App\Enums\DeadlineExpiryEnum;
use App\Enums\FeatureEnum;
use App\Enums\PublicationDateEnum;
use App\Exceptions\ApiHttpException;
use App\Facades\CompetitionsService;
use App\Http\Resources\Competitions\CompetitionResource;
use App\Models\SearchProfile;
use App\Models\User;
use App\Notifications\SearchProfiles\SearchProfileUpdateEmail;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class SearchProfileService
{
    public function getSearchProfiles(array $params, User $user)
    {
        if (!$user->hasFeature(FeatureEnum::SAVED_SEARCHES)) {
            throw new ApiHttpException(403, 'feature_not_available');
        }
        $itemsPerPage = $params['itemsPerPage'] ?? 5;
        $page = $params['page'] ?? 1;
        $isEmailUpdates = isset($params['isEmailUpdates']) ? (bool) $params['isEmailUpdates'] : null;
        $searchProfiles = SearchProfile::where('user_id', $user->id)
            ->when($isEmailUpdates === true, function ($query) {
                $query->where('email_updates', true);
            })
            ->orderBy('id', 'desc')
            ->paginate(
                $itemsPerPage,
                ['*'],
                'page',
                $page
            );

        return $searchProfiles;
    }

    public function findById(int $id, User $user)
    {
        if (!$user->hasFeature(FeatureEnum::SAVED_SEARCHES)) {
            throw new ApiHttpException(403, 'feature_not_available');
        }
        $searchProfile = SearchProfile::where('id', $id)
            ->where('user_id', $user->id)
            ->first();

        if (!$searchProfile) {
            throw new ApiHttpException(404, 'item_not_found');
        }

        return $searchProfile;
    }

    public function create(array $data, User $user)
    {
        if (!$user->hasFeature(FeatureEnum::SAVED_SEARCHES)) {
            throw new ApiHttpException(403, 'feature_not_available');
        }
        $searchProfile = new SearchProfile;
        $searchProfile->name = $data['name'];
        $searchProfile->type = $data['type'];
        $searchProfile->filters = $data['filters'];
        $searchProfile->user_id = $user->id;
        $searchProfile->email_updates = $data['emailUpdates'] ?? false;
        $searchProfile->save();

        return $searchProfile;
    }

    public function update(int $id, array $data, User $user)
    {
        if (!$user->hasFeature(FeatureEnum::SAVED_SEARCHES)) {
            throw new ApiHttpException(403, 'feature_not_available');
        }
        $searchProfile = $this->findById($id, $user);

        if (array_key_exists('name', $data)) {
            $searchProfile->name = $data['name'];
        }
        if (array_key_exists('type', $data)) {
            $searchProfile->type = $data['type'];
        }
        if (array_key_exists('filters', $data)) {
            $searchProfile->filters = $data['filters'];
        }
        if (array_key_exists('emailUpdates', $data)) {
            $searchProfile->email_updates = $data['emailUpdates'];
        }
        $searchProfile->save();

        return $searchProfile;
    }

    public function processUpdateEmails()
    {
        $searchProfiles = SearchProfile::where('email_updates', true)->get();

        Log::info("Processing search profile update emails for " . $searchProfiles->count() . " profiles.");
        $skipped = 0;
        $error = 0;
        $success = 0;
        foreach ($searchProfiles as $profile) {
            if (!$profile->user->hasFeature(FeatureEnum::SAVED_SEARCHES)) {
                $skipped++;
                continue;
            }

            try {
                $this->processUpdateEmail($profile);
                $success++;
            } catch (\Exception $e) {
                $error++;
                // Log the error and continue processing other profiles
                Log::error("Error processing search profile update email for profile ID {$profile->id}: " . $e->getMessage());
            }
        }
        Log::info("Search profile update email processing completed. Success: {$success}, Skipped: {$skipped}, Errors: {$error}.");
    }

    public function processUpdateEmail(SearchProfile $profile)
    {
        $filters = $profile->filters;
        $lastUpdate = $profile->last_email_update;

        if ($lastUpdate) {
            // If $lastUpdate is more than a week a ago, limit to last week
            $oneWeekAgo = now()->subWeek();
            if ($lastUpdate->lessThan($oneWeekAgo)) {
                $lastUpdate = $oneWeekAgo;
            }

            // Set publication date filter to only get competitions published since last email update
            $filters['publicationDate'] = [
                'type' => PublicationDateEnum::SINCE->value,
                'value' => $lastUpdate->startOfDay()->toDateTimeString(),
            ];
        } else {
            // If no last update, set to last 1 day to avoid overwhelming results
            $filters['publicationDate'] = [
                'type' => PublicationDateEnum::LAST_1->value,
                'value' => null,
            ];
        }

        // Override certain filters to ensure only relevant competitions are fetched
        $filters['deadlineExpiry'] = [
            'type' => DeadlineExpiryEnum::ALL_VALID->value,
            'value' => null,
        ];

        $params = [
            'itemsPerPage' => 250, // Max items per email
            'page' => 1,
            'filters' => $filters,
        ];
        $competitions = CompetitionsService::getCompetitions($params, null)->items();

        // We transform competitions using CompetitionResource to lower payload size on queue
        $competitionsData = CompetitionResource::collection($competitions)->resolve();

        if (count($competitions) > 0) {
            // Send email notification to user about new competitions
            $profile->user->notify(
                (new SearchProfileUpdateEmail($profile, $competitionsData)) // ->delay(now()->setMinute(26))
            );
            // Update last email update timestamp
            $profile->last_email_update = now();
            $profile->save();
        }
    }
}
