<?php

declare(strict_types=1);

namespace Tests\Framework\LiveComponents;

use App\Framework\Filesystem\InMemoryStorage;
use App\Framework\LiveComponents\Services\IntegrityValidator;
use App\Framework\LiveComponents\ValueObjects\ChunkHash;

beforeEach(function () {
    $this->validator = new IntegrityValidator();
    $this->fileStorage = new InMemoryStorage();
});

test('verifies chunk data with correct hash', function () {
    $chunkData = str_repeat('A', 512);
    $correctHash = ChunkHash::fromData($chunkData);

    $result = $this->validator->verifyChunk($chunkData, $correctHash);

    expect($result)->toBeTrue();
});

test('rejects chunk data with incorrect hash', function () {
    $chunkData = str_repeat('A', 512);
    $wrongHash = ChunkHash::fromData('different data');

    $result = $this->validator->verifyChunk($chunkData, $wrongHash);

    expect($result)->toBeFalse();
});

test('calculates correct chunk hash', function () {
    $chunkData = str_repeat('B', 1024);

    $calculatedHash = $this->validator->calculateChunkHash($chunkData);
    $expectedHash = ChunkHash::fromData($chunkData);

    expect($calculatedHash->toString())->toBe($expectedHash->toString());
});

test('verifies file with correct hash', function () {
    $filePath = '/tmp/test-file.txt';
    $content = 'Test file content for hash verification';
    $this->fileStorage->put($filePath, $content);

    $correctHash = ChunkHash::fromFile($filePath);
    $result = $this->validator->verifyFile($filePath, $correctHash);

    expect($result)->toBeTrue();
});

test('rejects file with incorrect hash', function () {
    $filePath = '/tmp/test-file.txt';
    $content = 'Test file content';
    $this->fileStorage->put($filePath, $content);

    $wrongHash = ChunkHash::fromData('different content');
    $result = $this->validator->verifyFile($filePath, $wrongHash);

    expect($result)->toBeFalse();
});

test('returns false for non-existent file', function () {
    $nonExistentFile = '/tmp/does-not-exist.txt';
    $someHash = ChunkHash::fromData('some data');

    $result = $this->validator->verifyFile($nonExistentFile, $someHash);

    expect($result)->toBeFalse();
});

test('calculates correct file hash', function () {
    $filePath = '/tmp/test-file.txt';
    $content = 'File content for hash calculation test';
    $this->fileStorage->put($filePath, $content);

    $calculatedHash = $this->validator->calculateFileHash($filePath);
    $expectedHash = ChunkHash::fromFile($filePath);

    expect($calculatedHash->toString())->toBe($expectedHash->toString());
});

test('verifies identical chunk hashes match', function () {
    $data = 'consistent test data';

    $hash1 = $this->validator->calculateChunkHash($data);
    $hash2 = $this->validator->calculateChunkHash($data);

    expect($this->validator->verifyChunk($data, $hash1))->toBeTrue();
    expect($this->validator->verifyChunk($data, $hash2))->toBeTrue();
    expect($hash1->toString())->toBe($hash2->toString());
});

test('detects modified chunk data', function () {
    $originalData = 'original chunk data';
    $originalHash = ChunkHash::fromData($originalData);

    $modifiedData = 'modified chunk data';
    $result = $this->validator->verifyChunk($modifiedData, $originalHash);

    expect($result)->toBeFalse();
});

test('handles empty chunk data', function () {
    $emptyData = '';
    $hash = $this->validator->calculateChunkHash($emptyData);

    expect($this->validator->verifyChunk($emptyData, $hash))->toBeTrue();
});

test('handles large chunk data', function () {
    // 5MB chunk
    $largeData = str_repeat('X', 5 * 1024 * 1024);
    $hash = $this->validator->calculateChunkHash($largeData);

    expect($this->validator->verifyChunk($largeData, $hash))->toBeTrue();
});

test('verifies file hash remains consistent', function () {
    $filePath = '/tmp/consistent-file.txt';
    $content = 'Consistent file content';
    $this->fileStorage->put($filePath, $content);

    $hash1 = $this->validator->calculateFileHash($filePath);
    $hash2 = $this->validator->calculateFileHash($filePath);

    expect($hash1->toString())->toBe($hash2->toString());
    expect($this->validator->verifyFile($filePath, $hash1))->toBeTrue();
    expect($this->validator->verifyFile($filePath, $hash2))->toBeTrue();
});
