<?php

namespace App\Services;

use App\Enums\DocumentTypeEnum;
use App\Models\Game;
use App\Models\Product;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;

trait GameService
{
    /**
     * Store new record
     *
     * @param array $data
     * @return Builder|Model
     */
    public static function store(array $data): Model|Builder
    {
        return Game::query()->create($data);
    }

    /**
     * Update existing record
     *
     * @param array $data
     * @return mixed
     */
    public function updateService(array $data): mixed
    {
        return tap($this)->update($data);
    }

    /**
     * Create new game
     *
     * @param Product $product
     * @param string|null $cover
     * @param string|null $filePath
     * @return Model|Builder
     */
    public static function createNewGame(Product $product, string $cover = null, string $filePath = null): Model|Builder
    {
        return Game::store(array(
            'cover' => $cover,
            'file_path' => $filePath,
            'designation' => $product->{'designation'},
            'description' => $product->{'description'},
            'price' => $product->{'price'},
            'price_currency_id' => $product->{'price_currency_id'},
        ));
    }

    /**
     * @param int $id
     * @return Builder|Builder[]|Collection|Model|null
     */
    public static function findById(int $id): Model|Collection|Builder|array|null
    {
        return Game::query()->find($id);
    }

    /**
     * Create new game with cover file
     *
     * @param Product $product
     * @param string $basePath
     * @param UploadedFile $cover
     * @return Model|Builder|null
     */
    public static function createGameWithCover(Product $product, string $basePath, UploadedFile $cover): Model|Builder|null
    {
        $game = null;
        DB::beginTransaction();

        try {
            // Try to upload ...
            $resultPath = upload_file_system(DocumentTypeEnum::poster->value, $basePath, $cover);
            if(filled($resultPath)) {
                $game = self::createNewGame($product, $resultPath);
            }

            if($game !== null) {
                $product->updateService([
                    "game_id" => $game->{'id'},
                ]);

                DB::commit();
                return $game->refresh();
            }

            DB::rollBack();
        } catch (\Exception $exception) {
            log_debug(exception: $exception,  prefix: 'GameService::createGameWithCover');

            DB::rollBack();
        }

        return $game;
    }

    /**
     * Add game cover
     *
     * @param UploadedFile $uploadedFile
     * @param string $basePath
     * @return Game
     */
    public function addGameCover(UploadedFile $uploadedFile, string $basePath): Game
    {
        // Try to upload ...
        $resultPath = upload_file_system(DocumentTypeEnum::poster->value, $basePath, $uploadedFile);

        if(filled($resultPath)) {
            $this->updateService(array(
                "cover" => $resultPath,
            ));
        }

        return $this->refresh();
    }

    /**
     * Add game file
     *
     * @param Product $product
     * @param string $basePath
     * @param UploadedFile $gameFile
     * @return Model|Builder|null
     */
    public static function createGameWithFile(Product $product, string $basePath, UploadedFile $gameFile): Model|Builder|null
    {
        $game = null;
        DB::beginTransaction();

        try {
            // Try to upload ...
            $resultPath = upload_file_system(DocumentTypeEnum::gameFile->value, $basePath, $gameFile);
            if(filled($resultPath)) {
                $game = self::createNewGame($product, null, $resultPath);
            }

            if($game !== null) {
                $product->updateService([
                    "game_id" => $game->{'id'},
                ]);

                DB::commit();
                return $game->refresh();
            }

            DB::rollBack();
        } catch (\Exception $exception) {
            log_debug(exception: $exception,  prefix: 'GameService::createGameWithFile');

            DB::rollBack();
        }

        return $game;
    }

    /**
     * Try to add or update associated Game file
     *
     * @param UploadedFile $uploadedFile
     * @param string $basePath
     * @return Game
     */
    public function addGameFile(UploadedFile $uploadedFile, string $basePath): Game
    {
        // Try to upload ...
        $resultPath = upload_file_system(DocumentTypeEnum::gameFile->value, $basePath, $uploadedFile);

        if(filled($resultPath)) {
            $this->updateService(array(
                "file_path" => $resultPath,
            ));
        }

        return $this->refresh();
    }
}
