<?php

namespace App\Console\Commands\Broadcast;

use App\Console\Commands\BaseCommand;
use App\Events\SimplePrivateEvent;
use App\Models\Asns;
use Carbon\Carbon;
use App\Models\EventLease;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use Throwable;

class BroadcastMercuryRates extends BaseCommand
{

    protected $signature = 'broadcast:mercury-rates';

    protected $description = 'Broadcasts mercury traffic information.';

    protected $notEnterprise = true;

    public function __construct()
    {       
        parent::__construct();
    }

    public function handle()
    {

        $identities = EventLease::join('users', 'user_id', '=', 'users.id')
            ->join('product_rights', 'product_rights.organisation_id', '=', 'users.organisation_id')
            ->join('organisation_external_identities', 'organisation_external_identities.organisation_id', '=', 'users.organisation_id')
            ->where([
                ['leased_at', '>', Carbon::now()->subMinutes(2)],
                ['resource', '=', 'mercury'],
                ['product_rights.name', '=', 'mercury'],
                ['key', '=', 'gsl']
            ])
            ->whereNull('product_rights.deleted_at')
            ->whereNull('organisation_external_identities.deleted_at')
            ->select('users.organisation_id', 'identity')
            ->distinct()
            ->get();

        foreach($identities as $x) {

            // Top level identities
            $organisation_id = $x->organisation_id;
            $identity = $x->identity;

            // Reserve what we'll send per tunnel
            $tunnel_ids = [];
            $tunnel_bgps = [];
            $tunnel_99th = [];

            // Retrieve information

            try {
                $bgp = Http::withHeaders([
                        'Content-Type' => 'application/json'
                    ])
                    ->withHeaders([ 'X-API-Key' => env('tunnel_microservice_key') ])
                    ->timeout(2)
                    ->get(env('tunnel_microservice_url') . "/api/v1/bgp/cxid/$identity")
                    ->json();

            }
            catch(Throwable $t) {
                $bgp = [ 'endpoints' => [] ];
            }

            try {
                $billing = Http::withHeaders([
                        'Content-Type' => 'application/json'
                    ])
                    ->withHeaders([ 'X-API-Key' => env('tunnel_microservice_key') ])
                    ->timeout(2)
                    ->get(env('tunnel_microservice_url') . "/api/v1/billing/$identity")
                    ->json();

            }
            catch(Throwable $t) {
                $billing = [];
            }

            if((isset($billing['detail']) && str_contains($billing['detail'], 'not found')) || !isset($bgp['endpoints']) || !isset($billing['endpoints'])) {
                continue;
            }

            // Iterate over tunnels to spew events - We also need an endpoint to ID lookup... :(
            $endpoint_id_lookup = [];

            foreach($bgp['endpoints'] as $y) {

                // Skip if ASN not owned by user
                $has_asn = Asns::where([['asn', '=', $y['asn']], ['organisation_id', '=', $organisation_id], ['approved', '=', 1]])->count();

                if(!$has_asn) {
                    continue;
                }

                $tunnel_id      = $y['id'];
                $uptime         = $y['session']['established_time'];
                $max_routes     = $y['session']['max_total_routes'];
                $v4_routes      = $y['session']['v4_prefixes_received'];
                $v6_routes      = $y['session']['v6_prefixes_received'];
                $state          = $y['session']['state'];
                $prefixes       = $y['prefixes'];

                $endpoint_id_lookup[$y['endpoint_ip']] = $tunnel_id;

                $tunnel_bgps[$tunnel_id] = [
                    'uptime'        => $uptime,
                    'routes_max'    => $max_routes,
                    'routes_v6'     => $v6_routes,
                    'routes_v4'     => $v4_routes,
                    'state'         => $state,
                    'prefixes'      => $prefixes
                ];

                $tunnel_ids[] = $tunnel_id;
            }

            foreach($billing['endpoints'] as $y) {

                if(!isset($endpoint_id_lookup[$y['endpoint_ip']])) {
                    continue;
                }

                $tunnel_id  = $endpoint_id_lookup[$y['endpoint_ip']];

                $avg_combined_bps     = $y['avg_combined_bps'] === null ? 0 : ($y['avg_combined_bps'] / 1000000);
                $max_combined_bps     = $y['max_combined_bps'] === null ? 0 : ($y['max_combined_bps'] / 1000000);
                $p98_combined_bps     = $y['p98_combined_bps'] === null ? 0 : ($y['p98_combined_bps'] / 1000000);

                $tunnel_99th[$tunnel_id] = [
                    'avg' => $avg_combined_bps > 1000 ? (round($avg_combined_bps / 1000, 2) . ' Gbps') : (round($avg_combined_bps, 2) . ' Mbps'),
                    'max' => $max_combined_bps > 1000 ? (round($max_combined_bps / 1000, 2) . ' Gbps') : (round($max_combined_bps, 2) . ' Mbps'),
                    'p98' => $p98_combined_bps > 1000 ? (round($p98_combined_bps / 1000, 2) . ' Gbps') : (round($p98_combined_bps, 2) . ' Mbps')
                ];

                $tunnel_ids[] = $tunnel_id;

            }

            foreach($tunnel_ids as $tunnel_id) {

                SimplePrivateEvent::dispatch("tunnel.$tunnel_id", "mercury.$organisation_id", [
                    'rates' => $tunnel_99th[$tunnel_id] ?? null,
                    'bgp' => $tunnel_bgps[$tunnel_id] ?? null
                ]);

            }

            // Handle full 99ths for the organisation

            if(sizeof($billing) !== 0) {
                
                try {
                    $cx_timestamp            = $billing['cxid_level']['last_updated'];
                    $cx_avg_combined_bps     = $billing['cxid_level']['avg_combined_bps'] === null ? 0 : ($billing['cxid_level']['avg_combined_bps'] / 1000000);
                    $cx_max_combined_bps     = $billing['cxid_level']['max_combined_bps'] === null ? 0 : ($billing['cxid_level']['max_combined_bps'] / 1000000);
                    $cx_p98_combined_bps     = $billing['cxid_level']['p98_combined_bps'] === null ? 0 : ($billing['cxid_level']['p98_combined_bps'] / 1000000);

                    SimplePrivateEvent::dispatch("tunnel.billing", "mercury.$organisation_id", [
                        'avg' => $cx_avg_combined_bps > 1000 ? (round($cx_avg_combined_bps / 1000, 2) . ' Gbps') : (round($cx_avg_combined_bps, 2) . ' Mbps'),
                        'max' => $cx_max_combined_bps > 1000 ? (round($cx_max_combined_bps / 1000, 2) . ' Gbps') : (round($cx_max_combined_bps, 2) . ' Mbps'),
                        'p98' => $cx_p98_combined_bps > 1000 ? (round($cx_p98_combined_bps / 1000, 2) . ' Gbps') : (round($cx_p98_combined_bps, 2) . ' Mbps'),
                        'timestamp' => $cx_timestamp
                    ]);
                }
                catch(Throwable $t) {}
                
            }

        }

        return 0;
    }
}