<?php

namespace App\Http\Livewire;

use App\Models\Downloadable;
use App\Rules\ValidSqlDate;
use App\Services\Log;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
use Livewire\WithFileUploads;
use Livewire\WithPagination;
use Schema;

class Downloadables extends Component {
    use WithPagination;
    use WithFileUploads;

    protected string $paginationTheme = 'bootstrap';
    public $filterSearch, $bulkActionStatus, $deleteId, $downloadableId, $productId, $version, $numericVersion, $summary, $changelog, $releaseDate, $file, $published, $assignedAfter, $assignedBefore, $expiresBefore, $accessibleUntil, $bulkAction, $bulkItems, $bulkActionConfirm;

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

    protected function getCreateRules( $propertyName = '' ): array {

        $numericVersionMax = 0;
        if ( $propertyName == 'all' || $propertyName == 'numericVersion' ) {
            $numericVersionMax = Downloadable::where( 'product_id', $this->productId )
                                             ->max( 'numeric_version' );
        }

        return [
            'version'         => 'required',
            'numericVersion'  => 'required|numeric|min:' . ( $numericVersionMax + 1 ),
            'summary'         => 'required',
            'changelog'       => 'required',
            'releaseDate'     => [ 'required', 'date', new ValidSqlDate() ],
            'assignedAfter'   => [ new ValidSqlDate() ],
            'assignedBefore'  => [ new ValidSqlDate() ],
            'expiresBefore'   => [ new ValidSqlDate() ],
            'accessibleUntil' => [ new ValidSqlDate() ],
            'file'            => 'required|file|mimes:zip',
        ];
    }

    protected function getUpdateRules( $propertyName = '' ): array {
        $numericVersionMax = 0;
        if ( $propertyName == 'all' || $propertyName == 'numericVersion' ) {
            $numericVersionMax = Downloadable::where( 'product_id', $this->productId )
                                             ->max( 'numeric_version' );
        }

        return [
            'version'         => 'required',
            'numericVersion'  => 'required|numeric|min:' . (int) $numericVersionMax,
            'summary'         => 'required',
            'changelog'       => 'required',
            'releaseDate'     => [ 'required', 'date', new ValidSqlDate() ],
            'assignedAfter'   => [ new ValidSqlDate() ],
            'assignedBefore'  => [ new ValidSqlDate() ],
            'expiresBefore'   => [ new ValidSqlDate() ],
            'accessibleUntil' => [ new ValidSqlDate() ],
            'file'            => 'nullable|file|mimes:zip',
        ];
    }

    protected function getMessages(): array {
        return [
            'numericVersion.min' => __( 'Next numeric version should be :min or higher' )
        ];
    }

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

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

    public function createItem(): void {
	    if ( \Config::get( 'app.is_demo', false ) ) {
		    $this->dispatchBrowserEvent( 'show-toast', [
			    'toastType'    => 'danger',
			    'toastMessage' => __( 'This action is disabled in the demo!' )
		    ] );

		    return;
	    }

        $this->validate( $this->getCreateRules( 'all' ), $this->getMessages() );

        $item = new Downloadable();

        $item->product_id       = $this->productId;
        $item->version          = $this->version;
        $item->numeric_version  = $this->numericVersion;
        $item->update_summary   = $this->summary;
        $item->changelog        = $this->changelog;
        $item->release_date     = $this->releaseDate;
        $item->published        = $this->published ?? false;
        $item->assigned_after   = $this->assignedAfter;
        $item->assigned_before  = $this->assignedBefore;
        $item->expires_before   = $this->expiresBefore;
        $item->accessible_until = $this->accessibleUntil;

        $item->save();

        $this->file->storeAs( 'downloadables', $item->id . '.zip' );

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

    public function updateItem(): void {
	    if ( \Config::get( 'app.is_demo', false ) ) {
		    $this->dispatchBrowserEvent( 'show-toast', [
			    'toastType'    => 'danger',
			    'toastMessage' => __( 'This action is disabled in the demo!' )
		    ] );

		    return;
	    }

        $this->validate( $this->getUpdateRules( 'all' ), $this->getMessages() );

        $item = Downloadable::find( $this->downloadableId );

        $item->product_id       = $this->productId;
        $item->version          = $this->version;
        $item->numeric_version  = $this->numericVersion;
        $item->update_summary   = $this->summary;
        $item->changelog        = $this->changelog;
        $item->release_date     = $this->releaseDate;
        $item->published        = $this->published;
        $item->assigned_after   = empty( $this->assignedAfter ) ? null : $this->assignedAfter;
        $item->assigned_before  = empty( $this->assignedBefore ) ? null : $this->assignedBefore;
        $item->expires_before   = empty( $this->expiresBefore ) ? null : $this->expiresBefore;
        $item->accessible_until = empty( $this->accessibleUntil ) ? null : $this->accessibleUntil;

        $item->save();

        if ( $this->file != null ) {
            $this->file->storeAs( 'downloadables', $this->downloadableId . '.zip' );
        }

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


    public function deleteItem(): void {
	    if ( \Config::get( 'app.is_demo', false ) ) {
		    $this->dispatchBrowserEvent( 'show-toast', [
			    'toastType'    => 'danger',
			    'toastMessage' => __( 'This action is disabled in the demo!' )
		    ] );

		    return;
	    }

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

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

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


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

        $downloadable = Downloadable::find( $id );

        $this->downloadableId  = $downloadable->id;
        $this->productId       = $downloadable->product_id;
        $this->version         = $downloadable->version;
        $this->numericVersion  = $downloadable->numeric_version;
        $this->summary         = $downloadable->update_summary;
        $this->changelog       = $downloadable->changelog;
        $this->published       = $downloadable->published;
        $this->releaseDate     = $downloadable->release_date != null ? Carbon::parse( $downloadable->release_date )->format( 'Y-m-d' ) : '';
        $this->assignedAfter   = $downloadable->assigned_after != null ? Carbon::parse( $downloadable->assigned_after )->format( 'Y-m-d' ) : '';
        $this->assignedBefore  = $downloadable->assigned_before != null ? Carbon::parse( $downloadable->assigned_before )->format( 'Y-m-d' ) : '';
        $this->expiresBefore   = $downloadable->expires_before != null ? Carbon::parse( $downloadable->expires_before )->format( 'Y-m-d' ) : '';
        $this->accessibleUntil = $downloadable->accessible_until != null ? Carbon::parse( $downloadable->accessible_until )->format( 'Y-m-d' ) : '';

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

    public function resetInputs(): void {
        $this->deleteId        = null;
        $this->productId       = null;
        $this->version         = null;
        $this->numericVersion  = null;
        $this->summary         = null;
        $this->changelog       = null;
        $this->releaseDate     = Carbon::parse( now() )->format( 'Y-m-d' );
        $this->file            = null;
        $this->published       = null;
        $this->assignedAfter   = null;
        $this->assignedBefore  = null;
        $this->expiresBefore   = null;
        $this->accessibleUntil = null;

        $this->resetValidation();
    }

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

    public function bulkActionConfirmed(): void {
        if ( $this->bulkAction == 'delete' ) {
	        if ( \Config::get( 'app.is_demo', false ) ) {
		        $this->dispatchBrowserEvent( 'show-toast', [
			        'toastType'    => 'danger',
			        'toastMessage' => __( 'This action is disabled in the demo!' )
		        ] );

		        return;
	        }

            Downloadable::whereIn( 'id', $this->bulkItems )->delete();

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

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

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

            Log::add( '133', Auth::id(), request()->ip(), [ 'downloadable-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.downloadables.manage', [
            'downloadables' => Downloadable::where( function ( $q ) {
                if ( $this->filterSearch != '' ) {
                    foreach ( Schema::getColumnListing( 'downloadables' ) as $column ) {
                        $q->orWhere( $column, 'like', '%' . $this->filterSearch . '%' );
                    }
                }
            } )->orderBy( 'id', 'DESC' )->paginate( getOption( 'ui', 'itemsPerTable', 10 ) )
        ] );
    }
}
