<?php

namespace App\Services;

use App\Enums\DocumentTypeEnum;
use App\Enums\UserVerificationStatusEnum;
use App\Exceptions\UploadFileException;
use App\Exceptions\UserNameAlreadyExistException;
use App\Models\User;
use App\Models\UserDocument;
use App\Models\UserVerification;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

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

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

    /**
     * Request verification
     *
     * @param array $data
     * @return Builder|Model
     * @throws UploadFileException|UserNameAlreadyExistException
     */
    public static function requestVerification(array $data): Model|Builder
    {
        /** @var User $user */
        $user = auth()->user();

        DB::beginTransaction();
        try {
            //Check username does not already exist and if it does, it belongs to the Auth User
            User::checkUserUserNameUniqueness($data["user_name"]);

            $documentArray = match ($data["document_type"]) {
                config("torryme.document_types.cni") => config("torryme.document_array.cni"),
                config("torryme.document_types.driver_licence") => config("torryme.document_array.driver_licence"),
                config("torryme.document_types.passport") => config("torryme.document_array.passport"),
                default => null,
            };

            $userVerification = self::store([
                "first_name" => $data["first_name"],
                "last_name" => $data["last_name"],
                "date_of_birth" => $data["date_of_birth"],
                "user_name" => $data["user_name"],
                "status" => UserVerificationStatusEnum::pending->value,
                "rejection_reason" => null,
                "request_verification_user_id" => $user->{"id"},
                "treated_by_user_id" => null,
                "country_id" => $user->{"country"}->{"id"},
            ]);

            //Get user's current document path
            $userCurrentDocPath = sprintf(config('torryme.paths.docs'), User::$prefixDir . $user->{'id'});

            //Get user verification document path
            $verificationDocPath = sprintf($userCurrentDocPath . '/%s', UserVerification::$prefixDir . $userVerification->{"id"});

            foreach ($documentArray as $key => $value) {
                $documentType = match ($value) {
                    config("torryme.document_array.cni.front") => DocumentTypeEnum::cniFront->value,
                    config("torryme.document_array.cni.back") => DocumentTypeEnum::cniBack->value,
                    config("torryme.document_array.driver_licence.front") => DocumentTypeEnum::driverLicenceFront->value,
                    config("torryme.document_array.driver_licence.back") => DocumentTypeEnum::driverLicenceBack->value,
                    config("torryme.document_array.passport.front") => DocumentTypeEnum::passport->value,
                    default => null,
                };

                //Store identification documents
                $path = upload_image($documentType, $verificationDocPath, $data["" . $value]);

                if (!filled($path)) {
                    //TODO Delete verification documents in case of error
                    throw new UploadFileException(__('errors.unable_to_upload_verification_document'));
                }

                UserDocument::store([
                    "path" => $path,
                    "type" => $documentType,
                    "user_verification_id" => $userVerification->{"id"},
                ]);
            }

            //Store face scan image
            $faceScanPath = upload_image(DocumentTypeEnum::faceScan->value, $verificationDocPath, $data["face_scan"]);

            if (!filled($faceScanPath)) {
                //TODO Delete face scan video in case of error
                throw new UploadFileException(__('errors.unable_to_upload_verification_video'));
            }

            //Store face scan video
            UserDocument::store([
                "path" => $faceScanPath,
                "type" => DocumentTypeEnum::faceScan->value,
                "user_verification_id" => $userVerification->{"id"},
            ]);

            //Update user verification demand time
            $user->updateService(["verification_requested_at" => now()]);
            DB::commit();

            $result = $userVerification;
        } catch (Exception $exception) {
            log_debug(exception: $exception, prefix: 'UserVerificationService::requestVerification');

            DB::rollBack();
            throw $exception;
        }

        return $result;
    }

    /**
     * Check verification status
     *
     * @param User $user
     * @return Model|Builder|null
     */
    public static function checkStatus(User $user): Model|Builder|null
    {
        try {
            $userVerification = UserVerification::query()->where(
                "request_verification_user_id",
                $user->{"id"}
            )->latest()->first();

            $result = $userVerification;
        } catch (Exception $exception) {
            log_debug(exception: $exception, prefix: 'UserVerificationService::checkStatus');
            $result = null;
        }

        return $result;
    }
}
