<?php

namespace App\Http\Controllers\Billing;

use App\Http\Controllers\BaseController;
use App\Models\Billing\BillingCommit;
use App\Repositories\OverageRepository;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Throwable;

class AdminController extends BaseController
{
    public function get_overage_options() {

        try {
            $billing_information = Http::get(env('ENDPOINT_BILLING_MICROSERVICE_URL'), [ 'key' => env('ENDPOINT_BILLING_MICROSERVICE_SECRET')  ]);

            // Only accept valid services and then group them .
            $ungrouped_services = collect(array_filter($billing_information['billing_ids'], function($item) {
                
                foreach(['id', 'client_id', 'name'] as $key) {
                    if(!isset($item[$key])) {
                        return false;
                    }
                }

                return true;
            }));

            $services = [];

            foreach($ungrouped_services as $item) {

                $item['name'] = $item['name'] . ' (' . ($item['domain'] ?? 'DEDI or COLO') . ')';

                if(!isset($services[$item['client_id']])) {
                    $services[$item['client_id']] = [ $item ];
                }
                else {
                    $services[$item['client_id']][] = $item;
                }

            }

            // Organise the accounts. 
            $accounts = [
                'gsl'   => [],
                'sl'    => [],
                'gd'    => []
            ];

            foreach($billing_information['customer_ids'] as $item) {
                $relevant_services = [];

                if(isset($services[$item['id']])) {
                    
                    $brand = 'gsl';

                    if($item['id'] > 2000000) {
                        $brand = 'sl';
                    }
                    elseif($item['id'] > 1000000) {
                        $brand = 'gd';
                    }

                    foreach($services[$item['id']] as $service) {
                        $relevant_services[] = [
                            'id'        => $service['id'],
                            'name'      => $service['name'],
                            'latest'    => BillingCommit::where([['whmcs_brand', '=', $brand], ['whmcs_client_id', '=', $service['client_id']], ['whmcs_service_id', '=', $service['id']]])->first()->effective_at ?? null,
                        ];
                    }
                    
                    $accounts[$brand][] = [
                        'id'        => $item['id'],
                        'name'      => $item['name'],
                        'services'  => $relevant_services
                    ];
                }
            }
        }
        catch(Throwable $t) {
            $accounts = [];
        }

        return response()->json([
            'currencies' => [ 'USD', 'NZD', 'AUD', 'EUR', 'GBP' ],
            'brands' => [
                [ 'tag' => 'gsl', 'name' => 'Global Secure Layer' ],
                [ 'tag' => 'sl', 'name' => 'Streamline Servers' ],
                [ 'tag' => 'gd', 'name' => 'Go Dedicated' ]
            ],
            'accounts' => $accounts,
            'methods' => [ 'global' => 'Global', 'australian' => 'Australian Aggregate' ]
        ]);

    }

    public function get_overages(Request $_r) {

        return $this->paged_table($_r, function() {
            
            return BillingCommit::select(
                'id',
                'effective_at',
                'billing_day',
                'commit',
                'price_per_unit',
                'currency',
                'whmcs_brand',
                'whmcs_client_id',
                'whmcs_service_id',
                'search_name',
                'search_service',
                'search_brand',
                'method'
            );

        }, [ 

            'effective_at'      => [ 'db' => 'effective_at', 'searchable' => true ],
            'billing_day'       => [ 'db' => 'billing_day', 'searchable' => true ],
            'commit'            => [ 'db' => 'commit', 'searchable' => true ],
            'price_per_unit'    => [ 'db' => 'price_per_unit', 'searchable' => true ],
            'currency'          => [ 'db' => 'currency', 'searchable' => true ],
            
            'search_name'       => [ 'db' => 'search_name', 'searchable' => true ],
            'search_service'    => [ 'db' => 'search_service', 'searchable' => true ],
            'search_brand'      => [ 'db' => 'search_brand', 'searchable' => true ],

            'method'            => [ 'db' => 'method', 'searchable' => false ]

        ], 'effective_at', function($rows) {

            // We just handle whether or not a commit can produce a graph through this.
            $valid_identities = BillingCommit::selectRaw('MAX(id) as id')->where([['effective_at', '<=', now()]])->groupBy('whmcs_brand', 'whmcs_client_id', 'whmcs_service_id')->get()->keyBy('id');

            foreach($rows as $key => $row) {
                $rows[$key]['latest'] = isset($valid_identities[$row['id']]);
            }

            return $rows;

        });

    }

    public function add_overage(Request $_r) {

        // Retrieve existing options
        $options = $this->get_overage_options()->original;

        $valid_request = !Validator::make([
            'effective_at'      => $_r->input('effective_at'),
            'billing_day'       => $_r->input('billing_day'),
            'commit'            => $_r->input('commit'),
            'price_per_unit'    => $_r->input('price_per_unit'),
            'currency'          => $_r->input('currency'),
            'whmcs_brand'       => $_r->input('whmcs_brand'),
            'whmcs_service_id'  => $_r->input('whmcs_service_id'),
            'whmcs_client_id'   => $_r->input('whmcs_client_id'),
            'method'            => $_r->input('method')
        ], [
            'effective_at'      => ['required', 'date'],
            'billing_day'       => ['required', 'integer', 'max:28', 'min:1'],
            'commit'            => ['required', 'integer', 'min:1'],
            'price_per_unit'    => ['required', 'numeric', 'min:0'],
            'currency'          => ['required', Rule::in($options['currencies'])],
            'whmcs_brand'       => ['required', Rule::in(array_keys($options['accounts']))],
            'whmcs_service_id'  => ['required', 'integer', 'min:0'],
            'whmcs_client_id'   => ['required', 'integer', 'min:0'],
            'method'            => ['required', Rule::in([ 'global', 'australian' ])]
        ])->fails();

        \Log::debug(Validator::make([
            'effective_at'      => $_r->input('effective_at'),
            'billing_day'       => $_r->input('billing_day'),
            'commit'            => $_r->input('commit'),
            'price_per_unit'    => $_r->input('price_per_unit'),
            'currency'          => $_r->input('currency'),
            'whmcs_brand'       => $_r->input('whmcs_brand'),
            'whmcs_service_id'  => $_r->input('whmcs_service_id'),
            'whmcs_client_id'   => $_r->input('whmcs_client_id'),
            'method'            => $_r->input('method')
        ], [
            'effective_at'      => ['required', 'date'],
            'billing_day'       => ['required', 'integer', 'max:28', 'min:1'],
            'commit'            => ['required', 'integer', 'min:1'],
            'price_per_unit'    => ['required', 'numeric', 'min:0'],
            'currency'          => ['required', Rule::in($options['currencies'])],
            'whmcs_brand'       => ['required', Rule::in(array_keys($options['accounts']))],
            'whmcs_service_id'  => ['required', 'integer', 'min:0'],
            'whmcs_client_id'   => ['required', 'integer', 'min:0'],
            'method'            => ['required', Rule::in([ 'global', 'australian' ])]
        ])->errors());

        if($valid_request) {

            // We also need to make sure that the effective at is later than any prior effective at
            $known_overages_bigger = BillingCommit::where([
                ['whmcs_brand', '=', $_r->input('whmcs_brand')],
                ['whmcs_service_id', '=', $_r->input('whmcs_service_id')],
                ['whmcs_client_id', '=', $_r->input('whmcs_client_id')],
                ['effective_at', '>=', $_r->input('effective_at')]
            ])
            ->count();

            $existing_account = array_values(array_filter($options['accounts'][$_r->input('whmcs_brand')], function($x) use($_r) {
                return $x['id'] == $_r->input('whmcs_client_id');
            }));
            
            $existing_service = sizeof($existing_account) == 0 ? [] : array_values(array_filter($existing_account[0]['services'], function($x) use($_r) {
                return $x['id'] == $_r->input('whmcs_service_id');
            }));

            if(sizeof($existing_account) == 1 && sizeof($existing_service) == 1 && $known_overages_bigger == 0) {

                $new_commit = new BillingCommit([
                    'effective_at'      => $_r->input('effective_at'),
                    'billing_day'       => $_r->input('billing_day'),
                    'commit'            => $_r->input('commit'),
                    'price_per_unit'    => $_r->input('price_per_unit'),
                    'currency'          => $_r->input('currency'),
                    'whmcs_brand'       => $_r->input('whmcs_brand'),
                    'whmcs_client_id'   => $_r->input('whmcs_client_id'),
                    'whmcs_service_id'  => $_r->input('whmcs_service_id'),
                    'search_service'    => $existing_service[0]['name'],
                    'search_name'       => $existing_account[0]['name'],
                    'search_brand'      => strtoupper($_r->input('whmcs_brand')),
                    'method'            => $_r->input('method')
                ]);

                if($new_commit->save()) {
                    return response()->json([
                        'outcome' => 'SUCCESS'
                    ]);
                }
            }
        }

        return response()->json(['outcome' => 'FAILURE'], 400);
    }

    public function get_chart(Request $_r) {

        // Check whether the commit is the latest one
        $valid_request = !Validator::make([
            'service_id'      => $_r->input('service_id'),
            'period'        => $_r->input('period')
        ], [
            'service_id' => ['required', Rule::in(BillingCommit::selectRaw('MAX(id) as id')->where([['effective_at', '<=', now()]])->groupBy('whmcs_brand', 'whmcs_client_id', 'whmcs_service_id')->get()->pluck('id'))],
            'period'    => ['required', 'integer']    
        ])->fails();

        if($valid_request) {
            // Retrieve the graph in question
            $commit = BillingCommit::find($_r->input('service_id'));

            $now = Carbon::now();

            $start = Carbon::createFromDate($now->year, $now->month, $commit->billing_day, 'Australia/Sydney')->setHour(0)->setMinutes(0)->setSeconds(0)->subMonths($_r->input('period'));
            $finish = Carbon::createFromDate($now->year, $now->month, $commit->billing_day, 'Australia/Sydney')->setHour(23)->setMinutes(59)->setSeconds(59)->addMonth()->subMonths($_r->input('period'))->subDay();

            $o_repo = new OverageRepository();

            $version_to_use = 2;

            if($commit->whmcs_brand !== 'gsl' && $start->unix() < Carbon::createFromDate(2026, 8, 31, 'Australia/Sydney')->setHour(23)->setMinutes(59)->setSeconds(59)->unix()) {
                $version_to_use = 1;
            }

            if($commit->whmcs_client_id == 1000659 && $start->unix() > Carbon::createFromDate(2026, 8, 31, 'Australia/Sydney')->setHour(23)->setMinutes(59)->setSeconds(59)->unix()) {
                $commit->method = 'australian';
            }

            return response()->json($o_repo->getGraph($commit->whmcs_brand, $commit->whmcs_client_id, $commit->whmcs_service_id, $commit->search_service, $start->timestamp, $finish->timestamp, $commit->commit, $commit->price_per_unit, $commit->currency, $version_to_use, $commit->method));
        }

        return response()->json([], 400);
    }

}