<?php

namespace App\Modules\Network\Commands;

use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Log;

use App\Modules\Network\Models\Prefixes;
use App\Modules\Network\Models\PrefixInclusions;

use App\Models\Asns;
use App\Models\Organisation;

use App\Helpers\Utility\RouteList;

use function PHPSTORM_META\type;

class PrefixImport extends \App\Console\Commands\BaseCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'prefix:import';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Import any prefixes that are not associated with known and approved ASNs';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $prefixes_from_new = collect(\Http::get("http://54.215.89.235/all.active.detailed.json")->json())->map(function($i) { return [ 'full' => $i['prefix'] ]; })->toArray();

        $all_prefixes = collect(
            array_merge(
                RouteList::get_routes_url('http://54.215.89.235/all.active.txt', false),
                RouteList::get_routes_url('http://54.215.89.235/all.v6.active.txt', false),
                PrefixInclusions::select(DB::raw("CONCAT(address,'/',mask) as full"), 'address as ip', 'mask as width')->get()->toArray(),
                $prefixes_from_new
            )
        )->pluck('full')->unique();

        // Reserve Carbon object...
        $now = Carbon::now();

        foreach($all_prefixes->chunk(env('CHUNK_SIZE')) as $prefix_chunk) {

            $to_insert = [];
            $cidr_insertion_list = [];
            $recently_seen = [];

            // Track prefixes to be aware of for this chunk
            $known_prefixes = Prefixes::select('id', DB::raw('concat("address", \'/\', "mask") as cidr'))
                ->whereIn(DB::raw('concat("address", \'/\', "mask")'), $prefix_chunk)
                ->get()
                ->keyBy('cidr');

            foreach($prefix_chunk as $prefix) {
                // Sanitise address for insertion
                [$address, $width] = explode('/', $prefix);

                $sanitised_address = inet_ntop(inet_pton($address)) . '/' . $width;

                // Check whether we've seen this address before...
                if(isset($known_prefixes[$sanitised_address])) {
                    $recently_seen[] = $known_prefixes[$sanitised_address]->id;
                }
                else {

                    $to_insert[] = [
                        'created_at' => $now,
                        'updated_at' => $now,
                        'deleted_at' => null,
                        'name' => '',
                        'address' => $address,
                        'mask' => $width,
                        'seen_at' => $now,
                        'still_announced' => 1,
                        'created_source' => 'prefix-list-uncrushed',
                        'organisation_id' => 1,
                        'asn_id' => null,
                    ];

                    $cidr_insertion_list[] = $sanitised_address;
                }
            }

            // Add in networks that need to be inserted.
            if($to_insert !== []) {
                foreach(array_chunk($to_insert, env('CHUNK_SIZE') / 4) as $insertion_chunk) {
                    DB::table('prefixes')->insert($insertion_chunk);
                }
                
                // Now we build and place in associations...
                $new_insertions = Prefixes::whereIn(DB::raw('concat("address", \'/\', "mask")'), $cidr_insertion_list)->pluck('id');

                $associations_to_insert = [];

                foreach($new_insertions as $id) {

                    $associations_to_insert[] = [
                        'created_at' => $now,
                        'updated_at' => $now,
                        'tenant_id' => 1,
                        'supernet_id' => null,
                        'subnet_id' => $id
                    ];
                }


                foreach(array_chunk($associations_to_insert, env('CHUNK_SIZE') / 4) as $insertion_chunk) {
                    DB::table('supernets')->insert($insertion_chunk);
                }
            }

            // Mark prefixes as recently seen
            if($recently_seen != []) {
                Prefixes::whereIn('id', $recently_seen)->update([
                    'seen_at' => $now,
                    'created_source' => 'prefix-list-uncrushed'
                ]);
            }

        };

        return 0;
    }
}
