<?php

namespace App\Jobs;

use App\Enums\PlatformEnum;
use App\Exceptions\PlatformAuthException;
use App\Models\PlatformAccount;
use App\Models\PlatformChannel;
use App\Modules\Lemmy\Services\LemmyApiService;
use App\Services\Log\LogSaver;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Cache;

class SyncChannelPostsJob implements ShouldBeUnique, ShouldQueue
{
    use Queueable;

    public function __construct(
        private readonly PlatformChannel $channel
    ) {
        $this->onQueue('sync');
    }

    public static function dispatchForAllActiveChannels(): void
    {
        $logSaver = app(LogSaver::class);

        PlatformChannel::with(['platformInstance', 'platformAccounts'])
            ->whereHas('platformInstance', fn ($query) => $query->where('platform', PlatformEnum::LEMMY))
            ->whereHas('platformAccounts', fn ($query) => $query->where('platform_accounts.is_active', true))
            ->where('platform_channels.is_active', true)
            ->get()
            ->each(function (PlatformChannel $channel) use ($logSaver) {
                self::dispatch($channel);
                $logSaver->info('Dispatched sync job for channel', $channel);
            });
    }

    public function handle(LogSaver $logSaver): void
    {
        $logSaver->info('Starting channel posts sync job', $this->channel);

        match ($this->channel->platformInstance->platform) {
            PlatformEnum::LEMMY => $this->syncLemmyChannelPosts($logSaver),
        };

        $logSaver->info('Channel posts sync job completed', $this->channel);
    }

    /**
     * @throws PlatformAuthException
     */
    private function syncLemmyChannelPosts(LogSaver $logSaver): void
    {
        try {
            /** @var Collection<int, PlatformAccount> $accounts */
            $accounts = $this->channel->activePlatformAccounts()->get();
            $account = $accounts->first();

            if (! $account) {
                throw new PlatformAuthException(PlatformEnum::LEMMY, 'No active account found for channel');
            }

            $api = $this->makeApiService($this->channel->platformInstance->url);
            $token = $this->getAuthToken($api, $account);

            $api->syncChannelPosts($token, $this->channel, $this->channel->channel_id);

            $logSaver->info('Channel posts synced successfully', $this->channel);
        } catch (Exception $e) {
            $logSaver->error('Failed to sync channel posts', $this->channel, [
                'error' => $e->getMessage(),
            ]);

            throw $e;
        }
    }

    /**
     * Seam for testing — LemmyApiService needs a per-instance URL so it cannot be
     * container-resolved. Override in tests to inject a mock.
     */
    protected function makeApiService(string $instanceUrl): LemmyApiService
    {
        return new LemmyApiService($instanceUrl);
    }

    /**
     * @throws PlatformAuthException
     */
    private function getAuthToken(LemmyApiService $api, PlatformAccount $account): string
    {
        $cacheKey = "lemmy_jwt_token_{$account->id}";
        $cachedToken = Cache::get($cacheKey);

        if ($cachedToken) {
            return $cachedToken;
        }

        if (! $account->username || ! $account->password) {
            throw new PlatformAuthException(PlatformEnum::LEMMY, 'Missing credentials for account');
        }

        $token = $api->login($account->username, $account->password);

        if (! $token) {
            throw new PlatformAuthException(PlatformEnum::LEMMY, 'Login failed for account');
        }

        Cache::put($cacheKey, $token, 3600);

        return $token;
    }
}
