<?php

namespace Ignite\Core\Tests\Unit\Files;

use Ignite\Core\Facades\FileEncryption;
use Ignite\Core\Files\File;
use Ignite\Core\Files\TemporaryFile;
use Ignite\Core\Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Storage;

class FileTest extends TestCase
{
    use WithFaker;

    /** @test */
    public function stores_a_reference_to_a_disk_and_path()
    {
        // Arrange
        Storage::fake();
        Storage::fake($otherDisk = config('filesystems.default').'_other');
        $onDefaultDisk = new File('default-disk-file.txt');
        $onOtherDisk = new File('other-disk-file.txt', $otherDisk);

        // Execute & Check
        $onDefaultDisk->assertMissing();
        $onOtherDisk->assertMissing();
        $this->assertEquals('other-disk-file.txt', $onOtherDisk->getRelativePath());
        $this->assertEquals('default-disk-file.txt', $onDefaultDisk->getRelativePath());
        $this->assertEquals($otherDisk, $onOtherDisk->getDisk());
        $this->assertEquals(config('filesystems.default'), $onDefaultDisk->getDisk());
    }

    /** @test */
    public function copies_from_one_file_to_another()
    {
        // Arrange
        Storage::fake('local');
        $fromFile = new File('from-file.txt');
        $fromFile->put($this->faker->sentence());
        $toFile = new File('to-file.txt');
        $otherFile = new File('other-file.txt');
        $otherFile->put('other content');

        // Execute
        $this->assertTrue($fromFile->copyToFile($toFile));
        $this->assertTrue($otherFile->copyToFile($otherFile));

        // Check
        $this->assertEquals($fromFile->get(), $toFile->get());
        $this->assertEquals($otherFile->get(), $otherFile->get());
        $otherFile->assertExists();
    }

    /** @test */
    public function tells_you_whether_one_file_is_the_same_as_another()
    {
        // Arrange
        Storage::fake();
        Storage::fake('some-disk');
        Storage::fake('some-disk2');

        // Execute & Check
        $this->assertTrue(
            File::new('some-file1.csv')->is(
                File::new('some-file1.csv')
            ),
            'Same files, on default disk'
        );
        $this->assertFalse(
            File::new('some-file1.csv')->is(
                File::new('some-file2.csv')
            ),
            'Different files, on default disk'
        );

        $this->assertTrue(
            File::new('some-file1.pdf', 'some-disk')->is(
                File::new('some-file1.pdf', 'some-disk')
            ),
            'Same files, with disk specified'
        );
        $this->assertFalse(
            File::new('some-file1.pdf', 'some-disk')->is(
                File::new('some-file2.pdf', 'some-disk')
            ),
            'Different files, same disk, disk specified'
        );
        $this->assertFalse(
            File::new('some-file1.pdf', 'some-disk')->is(
                File::new('some-file1.pdf', 'some-disk2')
            ),
            'Same filename, different disk'
        );
    }

    /** @test */
    public function allows_you_to_encrypt_it()
    {
        // Arrange
        Storage::fake();
        $file = new File('my-file.txt');
        $file->put('my contents');
        $fileEncrypter = FileEncryption::encrypter();

        // Execute
        $file->encrypt($fileEncrypter);

        // Check
        $this->assertEquals('my contents', $fileEncrypter->decrypt($file)->get());
    }

    /** @test */
    public function allows_you_to_decrypt_it()
    {
        // Arrange
        Storage::fake();
        $file = new File('my-file.txt.pgp');
        $file->put('my contents');
        FileEncryption::encrypter()->encrypt($file, $file);

        // Pre-Check
        $this->assertNotEquals('my contents', $file->get());

        // Execute
        $file->decrypt();

        // Check
        $this->assertEquals('my contents', $file->get());
    }

    /** @test */
    public function allows_you_to_encrypt_it_to_a_specified_destination()
    {
        // Arrange
        Storage::fake();
        $file = new File('my-file.txt');
        $file->put('my contents');
        $encryptedFile = new File('my-file.txt.pgp');
        $fileEncrypter = FileEncryption::encrypter('pgp');

        // Execute
        $file->encrypt('pgp', $encryptedFile);

        // Check
        $this->assertFalse($encryptedFile->is($file));
        $this->assertEquals('my contents', $fileEncrypter->decrypt($encryptedFile)->get());
        $this->assertNotEquals($encryptedFile->get(), $file->get());
    }

    /** @test */
    public function allows_you_to_decrypt_it_to_a_specified_destination()
    {
        // Arrange
        Storage::fake();
        $file = new File('my-file.txt.pgp');
        $file->put('my contents');
        $decryptedFile = new File('my-file.txt');
        $fileEncrypter = FileEncryption::encrypter();
        $fileEncrypter->encrypt($file, $file);

        // Execute
        $file->decrypt($fileEncrypter, $decryptedFile);

        // Check
        $this->assertFalse($decryptedFile->is($file));
        $this->assertNotEquals('my contents', $file->get());
        $this->assertEquals('my contents', $decryptedFile->get());
        $this->assertNotEquals($decryptedFile->get(), $file->get());
    }

    /** @test */
    public function can_be_copied_to_a_temporary_file()
    {
        // Arrange
        Storage::fake();
        $file = new File('name.txt');
        $file->put('some data');

        // Execute
        $tempFile = $file->copyToTemporary();

        // Check
        $this->assertNotInstanceOf(TemporaryFile::class, $file);
        $this->assertInstanceOf(TemporaryFile::class, $tempFile);
        $this->assertEquals($file->get(), $tempFile->get());
        $this->assertFalse($file->is($tempFile));
    }
}
