<?php

namespace Tests\App\Controllers\Api;

use App\Controllers\Api\FilesController;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockIncomingRequest;
use Config\App;
use Config\Services;

class FakeFilesRequest extends MockIncomingRequest
{
    public function __construct(private readonly array $gets = [])
    {
        parent::__construct(config(App::class), new URI('https://test.alrahmaisgl.org'), 'php://input', new UserAgent());
    }

    public function getGet($key = null, $filter = null, $default = null)
    {
        if ($key === null) {
            return $this->gets;
        }

        return $this->gets[$key] ?? $default;
    }
}

class FakeStreamResponse
{
    public array $headers = [];
    public string $body = '';

    public function setHeader(string $key, string $value)
    {
        $this->headers[$key] = $value;
        return $this;
    }

    public function setBody(string $body)
    {
        $this->body = $body;
        return $this;
    }
}

class TestableFilesController extends FilesController
{
    protected function respond($data = null, ?int $status = null, string $message = '')
    {
        $payload = $data;
        if (is_array($data) && isset($data['message'])) {
            $message = $data['message'] ?? $message;
            $payload = $data['data'] ?? $data;
        }

        return [
            'status' => true,
            'message' => $message,
            'data' => $payload,
            'code' => $status,
        ];
    }

    protected function error(string $message = 'An error occurred', int $code = 400, ?array $errors = null)
    {
        $payload = ['status' => false, 'message' => $message, 'code' => $code];
        if (!empty($errors)) {
            $payload['errors'] = $errors;
        }
        return $payload;
    }
}

class FilesControllerTest extends CIUnitTestCase
{
    private TestableFilesController $controller;

    protected function setUp(): void
    {
        parent::setUp();

        Services::resetSingle('session');

        $this->controller = new TestableFilesController();
        $response = new FakeStreamResponse();
        self::setPrivateProperty($this->controller, 'response', $response);
    }

    public function testReceiptRejectsInvalidFilename()
    {
        $response = $this->controller->receipt('../secret.txt');

        $this->assertFalse($response['status']);
        $this->assertSame(400, $response['code']);
    }

    public function testReceiptRejectsUnsupportedExtension()
    {
        $response = $this->controller->receipt('malware.exe');

        $this->assertFalse($response['status']);
        $this->assertSame(400, $response['code']);
    }

    public function testReceiptReturnsNotFoundWhenMissing()
    {
        $response = $this->controller->receipt('missing.pdf');

        $this->assertFalse($response['status']);
        $this->assertSame(404, $response['code']);
    }

    public function testIndexRejectsInvalidType()
    {
        $request = new FakeFilesRequest(['type' => 'avatars']);
        $this->controller->setRequest($request);

        $response = $this->controller->index();

        $this->assertFalse($response['status']);
        $this->assertSame(400, $response['code']);
    }

    public function testIndexReturnsFileList()
    {
        $request = new FakeFilesRequest(['type' => 'receipts']);
        $this->controller->setRequest($request);

        $response = $this->controller->index();

        $this->assertTrue($response['status']);
        $this->assertSame('Files retrieved successfully', $response['message']);
        $this->assertSame('receipts', $response['data']['type']);
        $this->assertGreaterThanOrEqual(0, $response['data']['count']);
        $names = array_column($response['data']['files'], 'name');
        $this->assertIsArray($names);
    }
}
