<?php

namespace App\Modules\Network\Commands;

use DB;
use Carbon\Carbon;

use App\Modules\Network\Models\Goliath\GoliathAttack;
use App\Modules\Network\Models\Goliath\GoliathAttackPrefix;
use App\Modules\Network\Models\Prefixes;
use App\Modules\Network\Helpers\ControllerCommons;

class GoliathMonitorAttackThread extends \App\Console\Commands\BaseCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'goliath:monitor-attacks-thread {--id-max=} {--id-mod=} {--hours=}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Monitors goliath appliances to see whether the agents are active.';

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

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        try {
            $start = microtime(true);

            GoliathAttack::select(
                'id',
                DB::raw('(
                    SELECT string_agg(id::text, \' \') 
                    FROM prefixes
                    WHERE
                        prefixes.deleted_at is null
                        AND family(prefixes.address) = 4
                        AND prefixes.mask > 16
                        AND (
                            (prefixes.mask = 32 and goliath_attacks.destination = prefixes.address)
                            OR CONCAT(goliath_attacks.destination,\'/32\')::cidr << concat(prefixes.address,\'/\',prefixes.mask)::cidr
                        )
                ) AS prefix_ids')
            )
            ->where('created_at', '>', Carbon::now()->subHours($this->option('hours')))
            ->where(DB::raw('id % ' . $this->option('id-max')), '=', $this->option('id-mod'))
            ->chunk(5000, function($attacks) use($start) {

                echo "\n[".$this->option('id-mod')."] Took: " . microtime(true) - $start;

                $to_insert = [];

                $known_association_lookup = GoliathAttackPrefix::leftJoin('goliath_attacks', 'attack_id', '=', 'goliath_attacks.id')
                    ->select(DB::raw('CONCAT(prefix_id, \'-\', attack_id) AS lookup_id'))
                    ->whereIn('attack_id', $attacks->pluck('id'))
                    ->orderBy('goliath_attack_prefixes.id', 'desc')
                    ->get()
                    ->keyBy('lookup_id');

                foreach($attacks as $attack) {
                    if($attack->prefix_ids != null) {
                        foreach(explode(' ', $attack->prefix_ids) as $prefix_id) {

                            if(!isset($known_association_lookup["$prefix_id-$attack->id"])) {
                                $to_insert[] = [
                                    'prefix_id' => $prefix_id,
                                    'attack_id' => $attack->id
                                ];
                            }
                        }
                    }
                }

                foreach(array_chunk($to_insert, env('CHUNK_SIZE') / 2) as $chunk) {
                    DB::table('goliath_attack_prefixes')->insert($chunk);
                } 
                echo "\nInserted " . sizeof($to_insert) . ' attack associations';
            });
        }
        catch(\Exception $ex) {
            \Log::debug($ex);
        }

        return 0;
    }
}