<?php

namespace App\Http\Livewire;

use App\Models\Generator;
use App\Models\LicenseKey;
use App\Rules\GeneratorFunctionExists;
use App\Services\Log;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use LaravelIdea\Helper\App\Models\_IH_Generator_C;
use Livewire\Component;
use Schema;

class Generators extends Component {

    protected string $paginationTheme = 'bootstrap';

    public $filterSearch, $productId, $deleteId, $updateId, $method, $functionName, $numberOfChunks, $chunkLength, $charset, $prefix, $suffix, $activationLimit, $validity, $status, $generateQuantity, $generateFor, $bulkAction, $bulkItems, $bulkActionStatus, $bulkActionConfirm;

    protected $listeners = [ 'createItem', 'generate', 'bulkAction', 'bulkActionConfirmed', 'filterItems' ];

    protected function getCreateRules(): array {
        return [
            'productId'       => 'required|unique:generators,product_id|exists:products,id',
            'method'          => 'required|in:uuid,chunk-system,custom',
            'functionName'    => [ 'required_if:method,custom', 'alpha', new GeneratorFunctionExists() ],
            'numberOfChunks'  => 'required_if:method,chunk-system|numeric|min:1',
            'chunkLength'     => 'required_if:method,chunk-system|numeric|min:1',
            'charset'         => 'required_if:method,chunk-system',
            'activationLimit' => 'required|numeric|min:0',
            'validity'        => 'required|numeric|min:0'
        ];
    }

    protected function getUpdateRules(): array {
        return [
            'productId'       => 'required|unique:generators,product_id,' . $this->updateId . '|exists:products,id',
            'method'          => 'required|in:uuid,chunk-system,custom',
            'functionName'    => [ 'required_if:method,custom', 'alpha', new GeneratorFunctionExists() ],
            'numberOfChunks'  => 'required_if:method,chunk-system|numeric|min:1',
            'chunkLength'     => 'required_if:method,chunk-system|numeric|min:1',
            'charset'         => 'required_if:method,chunk-system',
            'activationLimit' => 'required|numeric|min:0',
            'validity'        => 'required|numeric|min:0'
        ];
    }

    protected function getDeleteRules(): array {
        return [
            'deleteId' => 'required|exists:generators,id',
        ];
    }

    protected function getMessages(): array {
        return [
            'numberOfChunks.required_if' => __( 'The number of chunks field is required when method is chunk system.' ),
            'chunkLength.required_if'    => __( 'The chunk length field is required when method is chunk system.' ),
            'charset.required_if'        => __( 'The charset field is required when method is chunk system.' ),
            'productId.unique'           => __( 'Only one generator per product is allowed.' )
        ];
    }

    public function createItemUpdated( $propertyName ): void {
        $this->validateOnly( $propertyName, $this->getCreateRules() );
    }

    public function updateItemUpdated( $propertyName ): void {
        $this->validateOnly( $propertyName, $this->getUpdateRules() );
    }

    public function createItem(): RedirectResponse {
        $this->validate( $this->getCreateRules() );

        $generator = new Generator();
        $this->assignItemFields( $generator );

        Log::add( '116', Auth::id(), request()->ip(), [ 'generator-id' => $generator->id ] );

        $this->dispatchBrowserEvent( 'close-create-modal' );
        $this->resetInputs();

        return redirect()->back();
    }

    public function updateItem(): RedirectResponse {
        $this->validate( $this->getUpdateRules() );

        $generator = Generator::find( $this->updateId );

        $this->assignItemFields( $generator );

        Log::add( '117', Auth::id(), request()->ip(), [ 'generator-id' => $generator->id ] );

        $this->dispatchBrowserEvent( 'close-update-modal' );
        $this->resetInputs();

        return redirect()->back();
    }

    public function deleteItem(): RedirectResponse {
        $this->validate( $this->getDeleteRules() );

        Generator::find( $this->deleteId )->delete();

        Log::add( '118', Auth::id(), request()->ip(), [ 'generator-id' => $this->deleteId ] );

        $this->dispatchBrowserEvent( 'close-delete-modal' );
        $this->resetInputs();

        return redirect()->back();
    }

    public function openCreateModal(): void {
        $this->resetInputs();
        $this->dispatchBrowserEvent( 'open-create-modal' );
    }

    public function openUpdateModal( $id ): void {
        $this->resetInputs();

        $generator = Generator::find( $id );

        $this->updateId        = $generator->id;
        $this->productId       = $generator->product_id;
        $this->method          = $generator->method;
        $this->functionName    = $generator->function_name;
        $this->numberOfChunks  = $generator->number_of_chunks;
        $this->chunkLength     = $generator->chunk_length;
        $this->prefix          = $generator->prefix;
        $this->suffix          = $generator->suffix;
        $this->activationLimit = $generator->activation_limit;
        $this->validity        = $generator->validity;
        $this->status          = $generator->status;
        $this->charset         = $generator->charset;

        $this->dispatchBrowserEvent( 'open-update-modal', [
            'productId'   => $generator->product_id,
            'productName' => $generator->product ? $generator->product->name : sprintf( __( 'Product Not Found #%d' ), $this->productId )
        ] );
    }

    public function resetInputs(): void {
        $this->productId        = 0;
        $this->method           = '';
        $this->functionName     = '';
        $this->numberOfChunks   = '4';
        $this->chunkLength      = '4';
        $this->prefix           = '';
        $this->suffix           = '';
        $this->activationLimit  = '1';
        $this->validity         = '365';
        $this->status           = false;
        $this->charset          = '0123456789ABCDEF';
        $this->generateQuantity = 0;
        $this->generateFor      = 0;

        $this->resetValidation();
    }

    /**
     * @param Generator $generator
     *
     * @return void
     */
    public function assignItemFields( Generator $generator ): void {
        $generator->product_id       = $this->productId;
        $generator->method           = $this->method;
        $generator->function_name    = $this->functionName;
        $generator->number_of_chunks = $this->numberOfChunks;
        $generator->chunk_length     = $this->chunkLength;
        $generator->prefix           = $this->prefix;
        $generator->suffix           = $this->suffix;
        $generator->activation_limit = $this->activationLimit;
        $generator->validity         = $this->validity;
        $generator->status           = $this->status;
        $generator->charset          = $this->charset;

        $generator->save();
    }

    public function generate(): void {
	    if ( \Config::get( 'app.is_demo', false ) ) {
		    $this->dispatchBrowserEvent( 'show-toast', [
			    'toastType'    => 'danger',
			    'toastMessage' => __( 'The quantity generated is capped at 10 in the demo!' )
		    ] );

		    $this->generateQuantity = 10;
	    }

        $generator = Generator::find( $this->generateFor );
        if ( $generator ) {
            $generatedIds = [];

            if ( $generator->method == 'uuid' ) {
                for ( $generated = 0; $generated < $this->generateQuantity; $generated ++ ) {
                    do {
                        $generatedLicenseKey = $generator->prefix . Str::uuid()->toString() . $generator->suffix;
                    } while ( LicenseKey::where( 'license_key', $generatedLicenseKey )->count() > 0 );

                    $licenseKey                   = new LicenseKey();
                    $licenseKey->product_id       = $generator->product_id;
                    $licenseKey->license_key      = $generatedLicenseKey;
                    $licenseKey->activation_limit = $generator->activation_limit;
                    $licenseKey->validity         = $generator->validity;
                    $licenseKey->status           = 'available';

                    $licenseKey->save();

                    $generatedIds[] = $licenseKey->id;
                }
            } else if ( $generator->method == 'chunk-system' ) {
                for ( $generated = 0; $generated < $this->generateQuantity; $generated ++ ) {
                    do {
                        $generatedLicenseKey = $generator->prefix . generateLicenseKey( $generator->charset, $generator->number_of_chunks, $generator->chunk_length ) . $generator->suffix;
                    } while ( LicenseKey::where( 'license_key', $generatedLicenseKey )->count() > 0 );

                    $licenseKey                   = new LicenseKey();
                    $licenseKey->product_id       = $generator->product_id;
                    $licenseKey->license_key      = $generatedLicenseKey;
                    $licenseKey->activation_limit = $generator->activation_limit;
                    $licenseKey->validity         = $generator->validity;
                    $licenseKey->status           = 'available';

                    $licenseKey->save();

                    $generatedIds[] = $licenseKey->id;
                }
            } else if ( $generator->method == 'custom' ) {
                for ( $generated = 0; $generated < $this->generateQuantity; $generated ++ ) {
                    do {
                        $generatedLicenseKey = $generator->prefix . call_user_func( $generator->function_name ) . $generator->suffix;
                    } while ( LicenseKey::where( 'license_key', $generatedLicenseKey )->count() > 0 );

                    $licenseKey                   = new LicenseKey();
                    $licenseKey->product_id       = $generator->product_id;
                    $licenseKey->license_key      = $generatedLicenseKey;
                    $licenseKey->activation_limit = $generator->activation_limit;
                    $licenseKey->validity         = $generator->validity;
                    $licenseKey->status           = 'available';

                    $licenseKey->save();

                    $generatedIds[] = $licenseKey->id;
                }
            }

            Log::add( '119', Auth::id(), request()->ip(), [ 'generator-id' => $this->generateFor, 'license-key-ids' => $generatedIds ] );
        }

        $this->dispatchBrowserEvent( 'generator-done' );
    }

    public function bulkAction(): void {
        $this->dispatchBrowserEvent( 'open-confirm-bulk-action' );
    }

    public function bulkActionConfirmed(): void {
        if ( $this->bulkAction == 'delete' ) {
            Generator::whereIn( 'id', $this->bulkItems )->delete();

            Log::add( '126', Auth::id(), request()->ip(), [ 'license-key-ids' => $this->bulkItems ] );

            $this->bulkAction = '';
            $this->bulkItems  = [];
        }

        if ( $this->bulkAction == 'change-status' && in_array( $this->bulkActionStatus, [ 'active', 'inactive' ] ) ) {
            Generator::whereIn( 'id', $this->bulkItems )->update( [ 'status' => $this->bulkActionStatus == 'active' ] );

            Log::add( '125', Auth::id(), request()->ip(), [ 'license-key-ids' => $this->bulkItems ] );

            $this->bulkAction       = '';
            $this->bulkActionStatus = '';
            $this->bulkItems        = [];
        }

        $this->dispatchBrowserEvent( 'close-confirm-bulk-action' );
        $this->dispatchBrowserEvent( 'reset-bulk-input' );
    }

    public function filterItems(): void {
        $this->dispatchBrowserEvent( 'filter-done' );
    }

    public function render() {
        return view( 'livewire.generators.manage', [
            'items'    => Generator::where( function ( $q ) {
                if ( $this->filterSearch != '' ) {
                    foreach ( Schema::getColumnListing( 'generators' ) as $column ) {
                        $q->orWhere( $column, 'like', '%' . $this->filterSearch . '%' );
                    }
                }
            } )->orderBy( 'id', 'DESC' )->paginate( getOption( 'ui', 'itemsPerTable', 10 ) ),
            'statuses' => LicenseKey::getStatuses(),
            'methods'  => Generator::getMethods(),
        ] );
    }
}
