<?php

namespace App\Repositories;

use App\Development\Reporting\Routes;
use App\Interfaces\ReportRepositoryInterface;
use Carbon\Carbon;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Throwable;

class ReportRepository implements ReportRepositoryInterface 
{

    public function __construct($_readonly = true)
    {

        // Testing mock endpoints. Development traffic is served centrally by the same
        // handlers via HttpMockServiceProvider; here we wire them explicitly for tests.
        if (env('APP_ENV') === 'testing') {
            $reporting = new Routes;

            Http::fake([
                '*/creatia-report/automation-destination-table*' => fn (Request $request) => $reporting->automation_table($request->data() ?? [], $request),
                '*/creatia-report/destination-table*'            => fn (Request $request) => $reporting->destination_table($request->data() ?? [], $request),
                '*/creatia-report/leaderboard*'                  => fn (Request $request) => $reporting->leaderboard($request->data() ?? [], $request),
                '*/creatia-report/destination-report*'           => fn (Request $request) => $reporting->report($request->data() ?? [], $request),
                '*/creatia-notification/start*'                  => fn (Request $request) => $reporting->notification($request->data() ?? [], $request),
            ]);
        }
    }

    /** Table Functions **/

    public function get_list_carpet($_filters, $_offset = 0, $_limit = 50, $_order = 'start_at', $_direction = 'DESC') {
        /*$where_clause = '';
        $where_conditions = [];
        $params = [];

        // We need an extra join if the organisation_id is provided so we can handle subtenanting...
        $extra_join = '';

        if(isset($_filters['organisation_id'])) {
            $extra_join = "LEFT JOIN report_carpet_subtenant ON report_carpet.carpet_id = report_carpet_subtenant.carpet_id";
        }

        foreach([
            'organisation_id' => "((:organisation_id = 1 AND report_carpet.creatia_organisation_id = 0) OR report_carpet.creatia_organisation_id = :organisation_id OR report_carpet_subtenant.creatia_organisation_id = :organisation_id)",
            'organisation' => "(organisation.name LIKE :organisation)",
            'destination' => "report_carpet.destination_addr::text LIKE :destination",
            'start_at' => "(report_carpet.start_at - INTERVAL 120 SECOND)::text LIKE :start_at",
            'finish_at' => "(report_carpet.finish_at + INTERVAL 120 SECOND)::text LIKE :finish_at",
            'global' => "(report_carpet.destination_addr::text LIKE :global OR (report_carpet.start_at - INTERVAL 120 SECOND)::text LIKE :global OR (report_carpet.finish_at + INTERVAL 120 SECOND)::text LIKE :global OR organisation.name LIKE :global)"
        ] as $key => $x) {
            if(isset($_filters[$key])) {
                
                $where_conditions[] = $x;

                if($key !== 'organisation_id') {
                    $params[$key] = '%' . $_filters[$key] . '%';
                }
                else {
                    $params[$key] = $_filters[$key];
                }
            }
        }

        if(sizeof($where_conditions) != 0) {
            $where_clause = ' AND ' . implode(' AND ', $where_conditions);
        }

        $filter_count = (int)$this->chh->selectUnpaged("WITH 
            max_metrics AS (
                SELECT 
                    carpet_id,
                    round(max(max_in_gbps), 2) AS max_gbps,
                    round(max(max_in_mpps), 2) AS max_mpps
                FROM report_carpet_info
                WHERE direction = 0 AND (max_in_gbps >= 1 AND max_in_mpps >= 0.1) OR (max_in_gbps >= 0.1 AND max_in_mpps >= 1)
                GROUP BY carpet_id
            ),
            singular_times AS (
                SELECT
                    carpet_id,
                    MIN(start_at) as start_at,
                    MAX(finish_at) as finish_at
                FROM
                    report_carpet_singular
                INNER JOIN
                    report_singular ON report_singular.singular_id = report_carpet_singular.singular_id
                WHERE
                    report_singular.finish_at > now()-7776000
                GROUP BY
                    carpet_id
            )
            SELECT
                count(DISTINCT rc.carpet_id) as count
            FROM
                report_carpet AS rc
            LEFT JOIN
                organisation AS org ON rc.creatia_organisation_id = org.id
            INNER JOIN
                max_metrics ON max_metrics.carpet_id = rc.carpet_id
            INNER JOIN
                singular_times ON singular_times.carpet_id = report_carpet.carpet_id
            $extra_join
            WHERE
                finish_at > now()-7776000 $where_clause
            ", $params)->get()[0]['count'];

        // Premature bailout on zero
        if($filter_count == 0) {
            return [
                'data' => [],
                'filtered' => 0,
                'returned' => 0
            ];
        }

        $items = collect($this->chh->select("WITH 
            max_metrics AS (
                SELECT 
                    carpet_id,
                    round(max(max_in_gbps), 2) AS max_gbps,
                    round(max(max_in_mpps), 2) AS max_mpps
                FROM report_carpet_info
                WHERE direction = 0 AND (max_in_gbps >= 1 AND max_in_mpps >= 0.1) OR (max_in_gbps >= 0.1 AND max_in_mpps >= 1)
                GROUP BY carpet_id
            ),
            singular_times AS (
                SELECT
                    carpet_id,
                    MIN(start_at) as start_at,
                    MAX(finish_at) as finish_at
                FROM
                    report_carpet_singular
                INNER JOIN
                    report_singular FINAL ON report_singular.singular_id = report_carpet_singular.singular_id
                WHERE
                    report_singular.finish_at > now()-7776000
                GROUP BY
                    carpet_id
            )
            SELECT DISTINCT
                report_carpet.carpet_id as report_id,
                singular_times.start_at - INTERVAL 120 SECOND as start_at,
                singular_times.finish_at + INTERVAL 120 SECOND as finish_at,
                report_carpet.destination_parent::IPv4 as destination,
                organisation.name as organisation,
                report_carpet.creatia_organisation_id as organisation_id,
                IF(report_carpet_complete.carpet_id = 0, 0, 1) AS ready,
                max_gbps AS gbps,
                max_mpps AS mpps
            FROM
                report_carpet
            INNER JOIN
                max_metrics ON max_metrics.carpet_id = report_carpet.carpet_id
            INNER JOIN
                singular_times ON singular_times.carpet_id = report_carpet.carpet_id
            LEFT JOIN
                organisation on report_carpet.creatia_organisation_id = organisation.id
            LEFT JOIN
                report_carpet_complete ON report_carpet.carpet_id = report_carpet_complete.carpet_id
            $extra_join
            WHERE
                singular_times.start_at > now()-7776000 $where_clause
            ORDER BY {order} {direction}", $_offset, $_limit, array_merge($params, [
                'order'     => $_order,
                'direction' => $_direction,
            ]))->get());

        return [
            'data' => $items,
            'filtered' => $filter_count,
            'returned' => sizeof($items)
        ];*/
    }

    public function get_list_singular($_draw, $_filters, $_offset = 0, $_limit = 50, $_order = 'start_at', $_direction = 'DESC') {

        try {
            $response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/destination-table', [
                'draw'      => (int)$_draw,
                'order'     => $_order ?? 'start_at',
                'direction' => $_direction ?? 'DESC',
                'limit'     => (int)$_limit ?? 100,
                'offset'    => (int)$_offset ?? 0,
                'filters'   => $_filters ?? []
            ]);

            if($response->successful()) {
                $result = $response->json();
             
                $result['data'] = collect($result['data']);
             
                return $result;
            }

        }
        catch(Throwable $t) {
            Log::error($t);
        }

        return [
            'draw' => intval($_draw),
            'recordsTotal' => 0,
            'recordsFiltered' => 0,
            'data' => []
        ];

    }

    public function get_list_automation_singular($_draw, $_filters, $_offset = 0, $_limit = 50, $_order = 'start_at', $_direction = 'DESC') {

        try {
            $response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/automation-destination-table', [
                'draw'      => $_draw,
                'order'     => $_order ?? 'start_at',
                'direction' => $_direction ?? 'DESC',
                'limit'     => $_limit ?? 500,
                'offset'    => $_offset ?? 0,
                'filters'   => $_filters ?? []
            ]);

            if($response->successful()) {
                $result = $response->json();
             
                $result['data'] = collect($result['data']);
             
                return $result;
            }

        }
        catch(Throwable $t) {
            Log::error($t);
        }

        return [
            'draw' => intval($_draw),
            'recordsTotal' => 0,
            'recordsFiltered' => 0,
            'data' => []
        ];

    }

    public function get_table_leaderboard($_draw, $_offset = 0, $_limit = 100, $_order = 'c_score', $_direction = 'DESC', $_start = null, $_finish = null, $_size = null) {

        try {
            $response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/leaderboard', [
                'draw'      => $_draw,
                'order'     => $_order ?? 'c_score',
                'direction' => $_direction ?? 'DESC',
                'limit'     => $_limit ?? 100,
                'offset'    => $_offset ?? 0,
                'start'     => Carbon::parse($_start)->unix() ?? Carbon::now()->subDays(30)->unix(),
                'end'    => Carbon::parse($_finish)->unix() ?? Carbon::now()->unix(),
                'size'      => $_size ?? 100
            ]);

            if($response->successful()) {
                return $response->json();
            }

        }
        catch(Throwable $t) {
            Log::error($t);
        }

        return [
            'draw' => intval($_draw),
            'recordsTotal' => 0,
            'recordsFiltered' => 0,
            'data' => []
        ];
    }

    /** Report & Validation Functions **/

    public function get_report_carpet($_carpet_id) {
        $report_response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/carpet', [
            'report_id' => $_carpet_id
        ]);

        if($report_response->successful()) {
            return $report_response->body();
        }

        return false;
    }

    public function get_report_singular($_attack_id, $_organisation_id = null)
    {

        $payload = [ 'report_id' => $_attack_id ];

        if($_organisation_id !== null) {
            $payload['organisation_id'] = $_organisation_id;
        }

        $report_response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/destination-report', $payload);

        if($report_response->successful()) {
            return $report_response->body();
        }

        return false;
    }

    public function validate_report_singular($_attack_id)
    {
        $report_response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-report/destination-report', [
            'report_id' => $_attack_id,
            'validate' => 1
        ]);

        if($report_response->successful()) {
            return $report_response->json();
        }

        return false;
    }

    public function get_attack_start_sizes($_address, $_from, $_to, $_min_gbps, $_min_mpps) {
        
        try {
            $response = Http::timeout(300)->withBasicAuth('creatia', config('creatia.reporting.microservice_password'))->get(config('creatia.reporting.microservice_url') . '/creatia-notification/start', [
                'from'      => Carbon::parse($_from)->unix(),
                'to'        => Carbon::parse($_to)->unix(),
                'mpps'      => (int)$_min_mpps,
                'gbps'      => (int)$_min_gbps,
                'address'   => ltrim($_address, '::ffff:')
            ]);

            if($response->successful()) {
                return $response->json();
            }
            else {
                Log::error("Problem with `get_attack_start_sizes` detected.");
                Log::error("Specifically, an inappropriate return code was given.");
                Log::error([
                    'from'      => Carbon::parse($_from)->unix(),
                    'to'        => Carbon::parse($_to)->unix(),
                    'mpps'      => (int)$_min_mpps,
                    'gbps'      => (int)$_min_gbps,
                    'address'   => ltrim($_address, '::ffff:')
                ]);
                
            }

        }
        catch(Throwable $t) {
            Log::error("Problem with `get_attack_start_sizes` detected.");
            Log::error($t);
        }

        return [
            'data' => []
        ];
    }


}