<?php

declare(strict_types=1);

use App\Jobs\SyncBackendDataPool;
use Illuminate\Support\Facades\DB;

beforeEach(function () {
    // Clean up tables before each test
    DB::table('backend_data_pool')->truncate();
});

test('full sync truncates and rebuilds backend_data_pool', function () {
    // Arrange: Insert some old data
    DB::table('backend_data_pool')->insert([
        'transaction_id' => 999,
        'corporate_entity' => 'Old Company',
        'corporate_counterparty' => 'Old Counterparty',
        'tx_date' => '2024-01-01',
        'tx_amount' => 1000.00,
        'status' => 'done',
        'created_at' => '2024-01-01',
        'last_modified_at' => '2024-01-01',
        'prompt_id' => 1,
        'output_key' => 'test_key',
        'content' => 'test content',
        'synced_at' => now(),
    ]);

    expect(DB::table('backend_data_pool')->count())->toBe(1);

    // Act: Perform full sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Assert: Old data should be removed, new data from backend should be present
    $recordCount = DB::table('backend_data_pool')->count();
    expect($recordCount)->toBeGreaterThanOrEqual(0); // Should have backend data

    // Should not contain the old test record
    $oldRecord = DB::table('backend_data_pool')
        ->where('transaction_id', 999)
        ->first();

    expect($oldRecord)->toBeNull();
});

test('incremental sync only adds new records', function () {
    // Arrange: Perform initial sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    $initialCount = DB::table('backend_data_pool')->count();

    // Wait a moment to ensure timestamp difference
    sleep(1);

    // Act: Perform incremental sync (should not add duplicates)
    $incrementalJob = new SyncBackendDataPool(fullSync: false, batchSize: 100);
    $incrementalJob->handle();

    // Assert: Count should not increase significantly (only if new records in backend)
    $newCount = DB::table('backend_data_pool')->count();
    expect($newCount)->toBeGreaterThanOrEqual($initialCount);
});

test('sync correctly maps backend.transactions and backend.transaction_outputs', function () {
    // Act: Perform sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Assert: Check if records have correct structure
    $record = DB::table('backend_data_pool')->first();

    if ($record) {
        expect($record)->toHaveProperty('transaction_id');
        expect($record)->toHaveProperty('corporate_entity');
        expect($record)->toHaveProperty('corporate_counterparty');
        expect($record)->toHaveProperty('tx_date');
        expect($record)->toHaveProperty('tx_amount');
        expect($record)->toHaveProperty('status');
        expect($record)->toHaveProperty('prompt_id');
        expect($record)->toHaveProperty('output_key');
        expect($record)->toHaveProperty('content');
        expect($record)->toHaveProperty('synced_at');
    }
});

test('sync only includes transactions with status done', function () {
    // Act: Perform sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Assert: All records should have status = 'done'
    $nonDoneRecords = DB::table('backend_data_pool')
        ->where('status', '!=', 'done')
        ->count();

    expect($nonDoneRecords)->toBe(0);
});

test('sync processes records in batches', function () {
    // Act: Perform sync with small batch size
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 10);
    $job->handle();

    // Assert: Should complete without errors
    $recordCount = DB::table('backend_data_pool')->count();
    expect($recordCount)->toBeGreaterThanOrEqual(0);
});

test('getStats returns correct statistics', function () {
    // Arrange: Perform sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Act: Get stats
    $stats = $job->getStats();

    // Assert: Stats should have correct structure
    expect($stats)->toBeArray();
    expect($stats)->toHaveKey('backend_transactions_done');
    expect($stats)->toHaveKey('backend_transaction_outputs');
    expect($stats)->toHaveKey('backend_data_pool_records');
    expect($stats)->toHaveKey('last_synced_at');

    expect($stats['backend_data_pool_records'])->toBeGreaterThanOrEqual(0);
});

test('sync handles empty backend gracefully', function () {
    // This test assumes backend might be empty or have no 'done' transactions

    // Act: Perform sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Assert: Should complete without errors
    $recordCount = DB::table('backend_data_pool')->count();
    expect($recordCount)->toBeGreaterThanOrEqual(0);
});

test('sync orders records by transaction_id and prompt_id', function () {
    // Act: Perform sync
    $job = new SyncBackendDataPool(fullSync: true, batchSize: 100);
    $job->handle();

    // Assert: Check ordering
    $records = DB::table('backend_data_pool')
        ->limit(10)
        ->get();

    if ($records->count() > 1) {
        $previousTransactionId = null;
        $previousPromptId = null;

        foreach ($records as $record) {
            if ($previousTransactionId !== null) {
                // Either transaction_id should increase or stay same (with prompt_id increasing)
                expect($record->transaction_id)->toBeGreaterThanOrEqual($previousTransactionId);

                if ($record->transaction_id === $previousTransactionId && $previousPromptId !== null) {
                    expect($record->prompt_id)->toBeGreaterThanOrEqual($previousPromptId);
                }
            }

            $previousTransactionId = $record->transaction_id;
            $previousPromptId = $record->prompt_id;
        }
    }
});
