<?php

namespace App\Services;

use App\Enums\UserTypeEnum;
use App\Models\Address;
use App\Models\Client;
use App\Models\User;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

class UserService
{
    public function __construct(private readonly MediaService $mediaService) {}

    public function getAll(): Collection
    {
        return User::query()->orderBy('created_at', 'desc')->get();
    }

    public function findById(int $id): ?User
    {
        return User::find($id);
    }

    public function create(array $data): User
    {
        return User::create($data);
    }

    public function update(int $id, array $data): ?User
    {
        return DB::transaction(function () use ($id, $data): ?User {
            $model = User::with('provider')->find($id);

            if (! $model) {
                return null;
            }

            $hasGender = array_key_exists('gender', $data);
            $gender    = data_get($data, 'gender');

            unset($data['gender']);

            $model->update($data);

            if ($hasGender) {
                if (! $model->provider) {
                    throw ValidationException::withMessages([
                        'gender' => __('messages.gender_only_for_providers'),
                    ]);
                }

                $model->provider->update(['gender' => $gender]);
            }

            return $model->fresh(['provider.profileMedia', 'client.profileMedia']);
        });
    }

    public function delete(int $id): bool
    {
        $model = $this->findById($id);

        if (! $model) {
            return false;
        }

        return $model->delete();
    }

    //

    public function getUserTypes(): array
    {
        return UserTypeEnum::toArray();
    }

    public function me(): ?User
    {
        return User::with(['provider.profileMedia', 'provider.primaryBankAccount', 'client.profileMedia'])->find(Auth::id());
    }

    public function updateMe(array $data): User
    {
        try {
            DB::beginTransaction();

            $user = User::with(['client.profileMedia'])->findOrFail(Auth::id());

            Log::warning('[avatar-upload] UserService::updateMe iniciado', [
                'user_id'        => $user->id,
                'client_id'      => $user->client?->id,
                'has_avatar_key' => data_get($data, 'avatar') !== null,
                'avatar_is_file' => data_get($data, 'avatar') !== null && data_get($data, 'avatar') instanceof UploadedFile,
                'old_media_id'   => $user->client?->profile_media_id,
                'old_media_path' => $user->client?->profileMedia?->path,
            ]);

            $userFields = array_filter(
                array_intersect_key($data, array_flip(['name', 'email', 'phone', 'language', 'push_notifications_enabled'])),
                fn ($v) => $v !== null,
            );

            if (! empty($userFields)) {
                $user->update($userFields);
            }

            if (array_key_exists('document', $data)) {
                $client = $user->client ?? Client::create(['user_id' => $user->id]);

                $client->document = data_get($data, 'document');

                $client->save();
            }

            if (data_get($data, 'avatar') !== null && data_get($data, 'avatar') instanceof UploadedFile) {
                $client = $user->client ?? Client::create(['user_id' => $user->id]);

                Log::warning('[avatar-upload] Iniciando replaceFile para avatar do cliente', [
                    'client_id'      => $client->id,
                    'folder'         => "client/avatar/{$client->id}",
                    'has_old_media'  => $client->profileMedia !== null,
                    'old_media_id'   => $client->profileMedia?->id,
                    'old_media_path' => $client->profileMedia?->path,
                ]);

                $media = $this->mediaService->replaceFile(
                    newFile: data_get($data, 'avatar'),
                    folder: "client/avatar/{$client->id}",
                    source: 'client',
                    sourceId: $client->id,
                    old: $client->profileMedia,
                );

                Log::warning('[avatar-upload] replaceFile concluído — salvando profile_media_id', [
                    'client_id'      => $client->id,
                    'new_media_id'   => $media->id,
                    'new_media_path' => $media->path,
                ]);

                $client->profile_media_id = $media->id;

                $client->save();

                Log::warning('[avatar-upload] Client salvo com novo profile_media_id', [
                    'client_id'        => $client->id,
                    'profile_media_id' => $client->profile_media_id,
                ]);
            } else {
                Log::warning('[avatar-upload] Avatar NÃO processado no service', [
                    'isset_avatar'   => data_get($data, 'avatar') !== null,
                    'is_upload_file' => data_get($data, 'avatar') !== null ? (data_get($data, 'avatar') instanceof UploadedFile) : false,
                    'data_keys'      => array_keys($data),
                ]);
            }

            $user->load('client');

            $registrationComplete = ! empty($user->name)
              && ! empty($user->client?->document)
              && Address::where('source', 'client')->where('source_id', $user->client->id)->exists();

            if ($user->registration_complete !== $registrationComplete) {
                $user->registration_complete = $registrationComplete;

                $user->save();
            }

            DB::commit();

            return $user->fresh(['client.profileMedia']);
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('[avatar-upload] ERRO em UserService::updateMe', [
                'error'     => $e->getMessage(),
                'exception' => get_class($e),
                'file'      => $e->getFile(),
                'line'      => $e->getLine(),
            ]);

            throw $e;
        }
    }
}
