<?php

namespace Tests\Feature\Api\V1\FullSurface;

use Tests\Feature\Api\V1\FullSurface\Support\FullSurfaceE2EContractCase;

class ApiPolymorphicOwnershipBoundaryContractTest extends FullSurfaceE2EContractCase
{
    public function test_owner_type_and_owner_id_fields_cannot_be_overposted_by_low_privilege_users(): void
    {
        $routes = $this->apiRoutesContainingAny(['message', 'support', 'document', 'attachment', 'note', 'comment', 'contact', 'notification']);

        foreach (array_slice($routes, 0, 100) as $route) {
            $method = $this->primaryMethod($route);
            if (! in_array($method, ['POST', 'PUT', 'PATCH'], true)) {
                continue;
            }

            $uri = $route->uri();
            $payload = $this->payloadFor($method, $uri) + [
                'owner_type' => 'App\\Models\\User',
                'owner_id' => $this->admin->id,
                'created_by_type' => 'App\\Models\\User',
                'created_by_id' => $this->admin->id,
                'recipient_type' => 'administrator',
                'recipient_id' => $this->admin->id,
            ];

            $response = $this->requestAs($this->parent, $method, $uri, $payload);

            $this->assertStatusIn($response, [200, 201, 202, 204, 400, 401, 403, 404, 405, 409, 419, 422], 'polymorphic overpost ' . $method . ' ' . $uri);
            $this->assertNoServerError($response, 'polymorphic overpost ' . $method . ' ' . $uri);
            $this->assertStringNotContainsString('App\\Models\\User', $response->getContent(), $uri . ' must not leak model class names.');
        }
    }

    public function test_cross_actor_owner_queries_do_not_return_private_data(): void
    {
        $routes = $this->apiRoutesContainingAny(['messages', 'documents', 'attachments', 'notifications', 'notes', 'comments']);

        foreach (array_slice($routes, 0, 80) as $route) {
            if ($this->primaryMethod($route) !== 'GET') {
                continue;
            }

            $uri = $route->uri();
            $response = $this->actingAs($this->parent, 'api')->getJson($this->materializePath($uri) . '?owner_type=user&owner_id=' . $this->admin->id);

            $this->assertControlled($response, 'GET', $uri);
            $this->assertNoServerError($response, 'cross actor owner query ' . $uri);
            $this->assertStringNotContainsStringIgnoringCase($this->admin->email, $response->getContent(), $uri . ' must not leak admin-owned data to parent.');
        }
    }
}
