<?php

namespace App\Modules\Network\Commands;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;

use App\Modules\Network\Models\Prefixes;

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

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

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Reassociate known prefixes against known and approved ASNs. This only happens intra-organisation, where prefixes may have changed ASN.';

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

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        // Get a list of prefixes that belong to a given ASN - We're essentially creating an ASN to prefix dictionary...
        $originator_prefix_dictionary = [];
        $owner_prefix_dictionary = [];

        $prefix_owner_dictionary = [];

        foreach(collect(Http::get("http://54.215.89.235/all.active.detailed.json")->json()) as $announced_prefix) {
            
            if(!isset($originator_prefix_dictionary[$announced_prefix['asn_originator']])) {
                $originator_prefix_dictionary[$announced_prefix['asn_originator']] = array($announced_prefix['prefix']);
            }
            else {
                array_push($originator_prefix_dictionary[$announced_prefix['asn_originator']], $announced_prefix['prefix']);
            }

            if(!isset($owner_prefix_dictionary[$announced_prefix['asn_owner']])) {
                $owner_prefix_dictionary[$announced_prefix['asn_owner']] = array($announced_prefix['prefix']);
            }
            else {
                array_push($owner_prefix_dictionary[$announced_prefix['asn_owner']], $announced_prefix['prefix']);
            }

            $prefix_owner_dictionary[$announced_prefix['prefix']] = $announced_prefix['asn_owner'];
        }

        if(sizeof($originator_prefix_dictionary) === 0) {
            return 0;
        }

        // Simple ASN lookup table
        $asn_lookup = [];

        foreach(Asns::where('approved', '=', 1)->get() as $asn) {
            $asn_lookup[$asn->organisation_id][$asn->asn] = $asn->id;
        }

        foreach(Organisation::all() as $organisation) {
            if(isset($asn_lookup[$organisation->id]) && sizeof($asn_lookup[$organisation->id]) > 1) {
                
                foreach($asn_lookup[$organisation->id] as $asn => $id) {

                    $query_values = [];
                    
                    // Handle originators first, here we'll make sure to exclude anything that has an owner...
                    $valid_dictionary_prefixes = [];

                    foreach((isset($originator_prefix_dictionary[$asn]) ? $originator_prefix_dictionary[$asn] : []) as $prefix) {

                        // If owner ASN exists in Creatia, then we shouldn't do this...
                        if(!(isset($asn_lookup[$organisation->id][$prefix_owner_dictionary[$prefix]]) && isset($prefix_owner_dictionary[$prefix]))) {
                            $valid_dictionary_prefixes[] = $prefix;
                        }
                    }

                    $relevant_prefix_ids = Prefixes::whereIn(DB::raw('concat("address", \'/\', "mask")'), $valid_dictionary_prefixes)
                        ->where([
                            ['organisation_id', '=', $organisation->id],
                            ['asn_id', '!=', $id]
                        ])
                        ->get()
                        ->pluck('id');

                    $query_values[] = [
                        'relevant' => $relevant_prefix_ids,
                        'asn_id' => $id
                    ];

                    // Handle owners...
                    if(isset($owner_prefix_dictionary[$asn])) {
                        $query_values[] = [
                            'relevant' => Prefixes::whereIn(DB::raw('concat("address", \'/\', "mask")'), $owner_prefix_dictionary[$asn])
                                ->where([
                                    ['organisation_id', '=', $organisation->id],
                                    ['asn_id', '!=', $id]
                                ])
                                ->get()
                                ->pluck('id'),
                            'asn_id' => $id
                        ];
                    }

                    DB::transaction(function() use($query_values, $organisation) {
                        try {
                            foreach($query_values as $x) {
                                if(sizeof($x['relevant'])) {
                                    \Log::debug("CONVERTING TO " . $x['asn']);
                                    \Log::debug($x['relevant']);
                                    \Log::debug("END OF ASN CHANGE SUMMARY");
        
                                    Prefixes::whereIn('id', $x['relevant'])->where('organisation_id', '=', $organisation->id)->update([
                                        'asn_id' => $x['asn_id']
                                    ]);
                                }
                            }
                            return true;
                        }
                        catch(\Exception $x) {
                            \Log::debug($x);
                        }
                    });
                }
            }
        }
        
        return 0;
    }
}
