<?php

namespace Tests\Feature;

use App\Models\Asns;
use App\Models\Goliath\GoliathAppliance;
use App\Models\Goliath\GoliathAsnAttributes;
use App\Models\Goliath\GoliathHistory;
use App\Models\Goliath\GoliathMetro;
use App\Models\Goliath\GoliathRegion;
use App\Models\Goliath\GoliathRuleset;
use App\Models\Goliath\GoliathSubregion;
use App\Models\Goliath\PrefixGoliathFirewall;
use App\Models\Goliath\PrefixGoliathFlag;
use App\Models\Goliath\PrefixGoliathInline;
use App\Models\Goliath\RulesetType;
use App\Models\Group;

use App\Models\Organisation;
use App\Models\Prefixes;
use App\Models\PrefixSubtenants;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;

/**
 *      @@@ TEST CERTIFICATION @@@
 *      This set of tests has been confirmed to be functioning as intended.
 * 
 *      Please note that this test is not to ensure the accuracy or veracity of audit log messages. It is just to confirm they generate, and are only visible to the right users.
 * 
 *      Please note that it is limited and requires tests for filters.
 *      
 *      Jesse Cunningham, 2026-04-21 4:00 PM AEST
 */

class GoliathAuditTest extends TestCase
{

    use RefreshDatabase;

    private $organisations = [];
    private $users = [];
    private $asns = [];
    private $prefixes = [];
    private $rulesets = [];
    private $regions = [];
    private $subregions = [];
    private $metros = [];

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

        // Setup organisations
        $this->organisations = [
            'A' => Organisation::create([ 'id' => 1, 'name' => 'A' ]),
            'B' => Organisation::create([ 'id' => 2, 'name' => 'B' ]),
            'C' => Organisation::create([ 'id' => 3, 'name' => 'C' ])
        ];

        // Setup users
        $group = Group::create([ 'name' => 'Test' ]);

        $default_user = [
            'phone'             => null,
            'password'          => '',
            'group_id'          => $group->id,
        ];

        $this->users = [
            'A' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['A']->id, 'name' => 'A', 'email' => 'creatia+1@globalsecurelayer.com' ]),
            'B' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['B']->id, 'name' => 'B', 'email' => 'creatia+2@globalsecurelayer.com' ]),
            'C' => User::create([ ...$default_user, 'organisation_id' => $this->organisations['C']->id, 'name' => 'C', 'email' => 'creatia+3@globalsecurelayer.com' ])
        ];

        // Setup ASNs
        $this->asns = [
            'A' => Asns::create([ 'asn' => 64512, 'organisation_id' => $this->organisations['A']->id, 'approved' => 1 ]),
            'B' => Asns::create([ 'asn' => 64513, 'organisation_id' => $this->organisations['B']->id, 'approved' => 1 ]),
            'C' => Asns::create([ 'asn' => 64514, 'organisation_id' => $this->organisations['C']->id, 'approved' => 1 ])
        ];

        // Setup rulesets
        $this->rulesets = [
            'A_UNIVERSAL'   => GoliathRuleset::create(['name' => 'A_UNIVERSAL', 'organisation_id' => $this->organisations['A']->id, 'type' => RulesetType::Universal->value, 'rules' => '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp"},{"matchAction":"drop","x":0,"y":200}]']),
            'A_PERSONAL'    => GoliathRuleset::create(['name' => 'A_PERSONAL', 'organisation_id' => $this->organisations['A']->id, 'type' => RulesetType::Reusable->value, 'rules' => '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp"},{"matchAction":"drop","x":0,"y":200}]']),
            'B_PERSONAL'    => GoliathRuleset::create(['name' => 'B_PERSONAL', 'organisation_id' => $this->organisations['B']->id, 'type' => RulesetType::Reusable->value, 'rules' => '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp"},{"matchAction":"drop","x":0,"y":200}]']),
        ];

        $this->regions = [
            '1' => GoliathRegion::create([ 'name' => '1', 'telemetry_identifier' => '1', 'visible' => 1 ]),
            '2' => GoliathRegion::create([ 'name' => '2', 'telemetry_identifier' => '2', 'visible' => 1 ]),
        ];


        $this->subregions = [
            '1' => GoliathSubregion::create([ 'name' => '1.1', 'telemetry_identifier' => '1.1', 'visible' => 1, 'region_id' => $this->regions['1']->id ]),
            '2' => GoliathSubregion::create([ 'name' => '2.1', 'telemetry_identifier' => '2.1', 'visible' => 1, 'region_id' => $this->regions['2']->id ]),
        ];

        $this->metros = [
            '1' => GoliathMetro::create([ 'name' => '1.1.1', 'telemetry_identifier' => '1.1.1', 'visible' => 1, 'region_id' => $this->regions['1']->id, 'subregion_id' => $this->subregions['1']->id ]),
            '2' => GoliathMetro::create([ 'name' => '2.1.1', 'telemetry_identifier' => '2.1.1', 'visible' => 1, 'region_id' => $this->regions['2']->id, 'subregion_id' => $this->subregions['2']->id ]),
        ];

        GoliathAppliance::create([ 'name' => '1', 'organisation_id' => $this->organisations['A']->id, 'registered_at' => Carbon::now(), 'region_id' => $this->regions['1']->id, 'subregion_id' => $this->subregions['1']->id, 'metro_id' => $this->metros['1']->id, 'authorised' => 1, 'address' => '126.0.0.1' ]);
        GoliathAppliance::create([ 'name' => '2', 'organisation_id' => $this->organisations['B']->id, 'registered_at' => Carbon::now(), 'region_id' => $this->regions['2']->id, 'subregion_id' => $this->subregions['2']->id, 'metro_id' => $this->metros['2']->id, 'authorised' => 1, 'address' => '126.0.0.1' ]);
        
        DB::table('goliath_history')->delete();
    }

    public function testAuditLog(): void
    {
        /**
         * Scenarios required:
         * 1. A prefix is created with specific properties
         * 2. A prefix is modified
         * 3. A prefix is taken out of inline (Got here)
         * 4. A prefix has a global ruleset set
         * 5. A prefix has a regional ruleset set
         * 6. A prefix is subtenanted to an organisation and then updated - It should ONLY be visible to the owner and subtenant - Repeat all above scenarios.
         * 7. A ruleset is created
         * 8. A ruleset is changed
         * 9. ASN defaults are changed
         * 10. Make sure a ruleset full entry is generated for an active ruleset
         */

        // Setup prefixes
        $organisation_a_prefix = Prefixes::factory()
            ->ownership($this->organisations['A'], $this->asns['A'])->inline(true)->flags(3, false)->firewall(null)
            ->create();

        $organisation_b_prefix = Prefixes::factory()
            ->ownership($this->organisations['B'], $this->asns['B'])->inline(true)->flags(3, false)->firewall(null)
            ->create();

        $organisation_c_prefix = Prefixes::factory()
            ->ownership($this->organisations['C'], $this->asns['C'])->inline(true)->flags(3, false)->firewall(null)
            ->create();

        // Scenario 1 

        // Check that the amount of entries returned for all organisations is correct. 
        $scenario_1_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_1_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_1_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_1_a) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_1_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_1_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_1_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_1_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_1_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 2
        $x = PrefixGoliathFlag::where('prefix_id', '=', $organisation_a_prefix->id)->get()->first();
        $x->flag_synproxy = 1;
        $x->save();

        $scenario_2_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_2_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_2_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_2_a) === 4, 'There should only be four GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_2_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_2_a->where('type', '=', 'Flags')) === 2, 'There should be two flag entries at this time.');

        $this->assertTrue(sizeof($scenario_2_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_2_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_2_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_2_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 3
        $x = PrefixGoliathInline::where('prefix_id', '=', $organisation_a_prefix->id)->get()->first();
        $x->forced = 0;
        $x->save();

        $scenario_3_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_3_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_3_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_3_a) === 5, 'There should only be five GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_3_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_3_a->where('type', '=', 'Inline')) === 2, 'There should be two inline entries at this time.');

        $this->assertTrue(sizeof($scenario_3_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_3_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_3_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_3_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 4
        $x = PrefixGoliathFirewall::create([
            'prefix_id' => $organisation_a_prefix->id,
            'ruleset_id' => $this->rulesets['A_UNIVERSAL']->id
        ]);

        $scenario_4_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_4_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_4_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_4_a) === 6, 'There should only be six GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_4_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_4_a->where('type', '=', 'Firewall')) === 2, 'There should be two firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_4_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_4_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_4_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_4_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 5
        $x = PrefixGoliathFirewall::create([
            'prefix_id' => $organisation_a_prefix->id,
            'ruleset_id' => $this->rulesets['A_UNIVERSAL']->id,
            'region_id' => $this->regions['1']->id
        ]);

        $scenario_5_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_5_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_5_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_5_a) === 7, 'There should only be seven GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_5_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_5_a->where('type', '=', 'Firewall')) === 3, 'There should be three firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_5_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_5_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_5_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_5_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 6

        PrefixSubtenants::insert([[
            'prefix_id' => $organisation_a_prefix->id,
            'subtenant_id' => $this->organisations['B']->id
        ]]);

        // Scenario 6.1 - Nothing should change in this state.

        // Check that the amount of entries returned for all organisations is correct. 
        $scenario_6_1_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_1_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_1_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_6_1_a) === 7, 'There should only be eight GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_1_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_6_1_b) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_1_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        $this->assertTrue(sizeof($scenario_6_1_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_1_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 6.2
        $x = PrefixGoliathFlag::where('prefix_id', '=', $organisation_a_prefix->id)->get()->first();
        $x->flag_synproxy = 0;
        $x->save();

        $scenario_6_2_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_2_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_2_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        $this->assertTrue(sizeof($scenario_6_2_a) === 8, 'There should only be eight GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_2_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_2_a->where('type', '=', 'Flags')) === 3, 'There should be three flag entries at this time.');

        $this->assertTrue(sizeof($scenario_6_2_b) === 4, 'There should only be four GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_2_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_2_b->where('type', '=', 'Flags')) === 2, 'There should be two flag entries at this time.');

        $this->assertTrue(sizeof($scenario_6_2_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_2_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 6.3
        $x = PrefixGoliathInline::where('prefix_id', '=', $organisation_a_prefix->id)->get()->first();
        $x->forced = 1;
        $x->save();

        $scenario_6_3_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_3_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_3_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_6_3_a) === 9, 'There should only be nine GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_3_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_3_a->where('type', '=', 'Inline')) === 3, 'There should be three inline entries at this time.');

        $this->assertTrue(sizeof($scenario_6_3_b) === 5, 'There should only be five GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_3_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_3_b->where('type', '=', 'Inline')) === 2, 'There should be two inline entries at this time.');

        $this->assertTrue(sizeof($scenario_6_3_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_3_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 6.4
        $x = PrefixGoliathFirewall::where([
            ['prefix_id', '=', $organisation_a_prefix->id],
            ['ruleset_id', '=', $this->rulesets['A_UNIVERSAL']->id]
        ])->whereNull('region_id')->get()->first();

        $x->delete();

        $scenario_6_4_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_4_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_4_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_6_4_a) === 10, 'There should only be ten GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_4_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_4_a->where('type', '=', 'Firewall')) === 4, 'There should be four firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_6_4_b) === 6, 'There should only be six GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_4_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_4_b->where('type', '=', 'Firewall')) === 2, 'There should be two firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_6_4_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_4_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 6.5
        $x = PrefixGoliathFirewall::where([
            ['prefix_id', '=', $organisation_a_prefix->id],
            ['ruleset_id', '=', $this->rulesets['A_UNIVERSAL']->id]
        ])->get()->first();

        $x->delete();

        $scenario_6_5_a = collect($this->actingAs($this->users['A'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_5_b = collect($this->actingAs($this->users['B'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);
        $scenario_6_5_c = collect($this->actingAs($this->users['C'])->withoutMiddleware()->get('/api/goliath/activity/mitigation?draw=0&start=0&length=50')->json()['data']);

        // There should be three audit messages for each organisation.
        
        $this->assertTrue(sizeof($scenario_6_5_a) === 11, 'There should only be eleven GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_5_a->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_5_a->where('type', '=', 'Firewall')) === 5, 'There should be five firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_6_5_b) === 7, 'There should only be seven GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_5_b->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_5_b->where('type', '=', 'Firewall')) === 3, 'There should be tthree firewall entries at this time.');

        $this->assertTrue(sizeof($scenario_6_5_c) === 3, 'There should only be three GoliathHistory entries at this time.');
        $this->assertTrue(sizeof($scenario_6_5_c->unique('type')->whereIn('type', ['Firewall', 'Inline', 'Flags'])) === 3, 'There should only be three different types of GoliathHistory entries at this time.');

        // Ensure that there's been access integrity
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_a_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_b_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');
        $this->assertTrue(GoliathHistory::where('history', 'LIKE', "%$organisation_c_prefix->address%")->distinct('organisation_id')->count() === 1, 'There should only be ONE organisation_id for this prefix.');

        // Scenario 7
        GoliathRuleset::create(['name' => 'A_TEST', 'organisation_id' => $this->organisations['A']->id, 'type' => RulesetType::Reusable->value, 'rules' => '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp"},{"matchAction":"drop","x":0,"y":200}]']);
        GoliathRuleset::create(['name' => 'B_TEST', 'organisation_id' => $this->organisations['B']->id, 'type' => RulesetType::Reusable->value, 'rules' => '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp"},{"matchAction":"drop","x":0,"y":200}]']);

        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['A']->id]])->count() === 1, 'There should be one history ruleset entry for Org A');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['B']->id]])->count() === 1, 'There should be one history ruleset entry for Org B');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['C']->id]])->count() === 0, 'There should be no history ruleset entry for Org C');

        // Scenario 8
        $x = GoliathRuleset::where('name', '=', 'A_TEST')->get()->first();
        $x->rules = '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp and tcp"},{"matchAction":"drop","x":0,"y":200}]';
        $x->save();

        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['A']->id]])->count() === 2, 'There should be two history ruleset entries for Org A');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['B']->id]])->count() === 1, 'There should be one history ruleset entry for Org B');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Ruleset'], ['organisation_id', '=', $this->organisations['C']->id]])->count() === 0, 'There should be no history ruleset entry for Org C');

        // Scenario 9
        GoliathAsnAttributes::create([
            'asn_id'                => $this->asns['A']->id,
            'default_synproxy'      => 1,
            'default_inline'        => 1,
            'default_heuristics'    => 3
        ]);

        $this->assertTrue(GoliathHistory::where([['type', '=', 'Default'], ['organisation_id', '=', $this->organisations['A']->id]])->count() === 1, 'There should be one history default entry for Org A');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Default'], ['organisation_id', '=', $this->organisations['B']->id]])->count() === 0, 'There should be no history default entry for Org B');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'Default'], ['organisation_id', '=', $this->organisations['C']->id]])->count() === 0, 'There should be no history default entry for Org C');

        // Scenario 10
        PrefixGoliathFirewall::create([
            'prefix_id' => $organisation_a_prefix->id,
            'ruleset_id' => $this->rulesets['A_UNIVERSAL']->id
        ]);

        $x = GoliathRuleset::where('name', '=', 'A_UNIVERSAL')->get()->first();
        $x->rules = '[{"matchAction":"accept","x":0,"y":0,"bpfRule":"udp and tcp"},{"matchAction":"drop","x":0,"y":200}]';
        $x->save();

        $this->assertTrue(GoliathHistory::where([['type', '=', 'RulesetFull'], ['organisation_id', '=', $this->organisations['A']->id]])->count() === 1, 'There should be one history ruleset entry for Org A');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'RulesetFull'], ['organisation_id', '=', $this->organisations['B']->id]])->count() === 0, 'There should be no history ruleset entry for Org B');
        $this->assertTrue(GoliathHistory::where([['type', '=', 'RulesetFull'], ['organisation_id', '=', $this->organisations['C']->id]])->count() === 0, 'There should be no history ruleset entry for Org C');
    }

}
