<?php

namespace Tests\Feature\Controllers;

use App\GlobalContentRepository;
use App\Http\Middleware\EnforceGlobalContentRestriction;
use App\Scopes\GlobalContentVisibilityScope;
use Illuminate\Http\Request;
use Mtc\MercuryDataModels\GlobalContent;
use Tests\DatabaseTestCase;
use Tests\UserForTenant;

class GlobalElementControllerTest extends DatabaseTestCase
{
    use UserForTenant;

    private function nonMtcUser(): \Mtc\MercuryDataModels\User
    {
        $user = $this->getUser('Administrator');
        $user->givePermissionTo('edit-global-content');

        return $user;
    }

    /**
     * Create a global content entry with the restriction flag persisted. The
     * shared factory model does not list superadmin_only as fillable, so it is
     * assigned directly to make sure the column is written.
     */
    private function makeContent(bool $restricted)
    {
        $content = GlobalContent::factory()->create();
        $content->superadmin_only = $restricted;
        $content->save();

        return $content;
    }

    private function writeRequest($user): Request
    {
        $request = Request::create('/', 'POST', ['name' => 'x', 'superadmin_only' => true]);
        $request->setUserResolver(fn () => $user);

        return $request;
    }

    public function testIndexExcludesRestrictedContentForNonMtcUser()
    {
        GlobalContent::query()->delete();
        $this->makeContent(true);

        $response = $this->actingAs($this->nonMtcUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.global-elements.index'));

        $response->assertStatus(200);
        $this->assertCount(0, $response->json('data'));
    }

    public function testShowRestrictedContentBlockedForNonMtcUser()
    {
        $content = $this->makeContent(true);

        $response = $this->actingAs($this->nonMtcUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->getJson(route('content.global-elements.show', $content));

        $response->assertStatus(403);
    }

    public function testDestroyRestrictedContentBlockedForNonMtcUser()
    {
        $content = $this->makeContent(true);

        $response = $this->actingAs($this->nonMtcUser())
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('content.global-elements.destroy', $content));

        $response->assertStatus(403);
        $this->assertTrue(GlobalContent::query()->whereKey($content->id)->exists());
    }

    public function testDestroyRestrictedContentAllowedForMtcUser()
    {
        $content = $this->makeContent(true);

        $response = $this->actingAs($this->getUser('mtc'))
            ->withHeader('X-Tenant', tenant('id'))
            ->deleteJson(route('content.global-elements.destroy', $content));

        $response->assertStatus(200);
        $this->assertFalse(GlobalContent::query()->whereKey($content->id)->exists());
    }

    public function testVisibilityScopeHidesRestrictedContentFromNonMtcUser()
    {
        GlobalContent::query()->delete();
        $this->makeContent(false);
        $this->makeContent(true);

        $visible = (new GlobalContentVisibilityScope())
            ->apply(GlobalContent::query(), $this->nonMtcUser())
            ->count();

        $this->assertSame(1, $visible);
    }

    public function testVisibilityScopeShowsAllContentToMtcUser()
    {
        GlobalContent::query()->delete();
        $this->makeContent(false);
        $this->makeContent(true);

        $visible = (new GlobalContentVisibilityScope())
            ->apply(GlobalContent::query(), $this->getUser('mtc'))
            ->count();

        $this->assertSame(2, $visible);
    }

    public function testMiddlewareStripsSuperadminOnlyForNonMtcWrite()
    {
        $request = $this->writeRequest($this->nonMtcUser());

        (new EnforceGlobalContentRestriction(new GlobalContentRepository()))
            ->handle($request, fn () => response('ok'));

        $this->assertFalse($request->boolean('superadmin_only'));
    }

    public function testMiddlewareKeepsSuperadminOnlyForMtcWrite()
    {
        $request = $this->writeRequest($this->getUser('mtc'));

        (new EnforceGlobalContentRestriction(new GlobalContentRepository()))
            ->handle($request, fn () => response('ok'));

        $this->assertTrue($request->boolean('superadmin_only'));
    }

    public function testUserCanModifyUnrestrictedContent()
    {
        $repository = new GlobalContentRepository();
        $content = $this->makeContent(false);

        $this->assertTrue($repository->userCanModify($content, null));
    }

    public function testUserCannotModifyRestrictedContentWithoutMtcRole()
    {
        $repository = new GlobalContentRepository();
        $content = $this->makeContent(true);

        $this->assertFalse($repository->userCanModify($content, null));
    }

    public function testUserCanModifyRestrictedContentWithMtcRole()
    {
        $repository = new GlobalContentRepository();
        $content = $this->makeContent(true);

        $this->assertTrue($repository->userCanModify($content, $this->getUser('mtc')));
    }
}
