<?php

namespace App\Services;

use App\Enums\UserTypeEnum;
use App\Models\Address;
use App\Models\City;
use App\Models\Client;
use App\Models\State;
use App\Models\User;
use App\Services\Pagarme\PagarmeCustomerService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ClientService
{
    public function __construct(
        private readonly AuthService $authService,
        private readonly PagarmeCustomerService $pagarmeCustomerService,
        private readonly MediaService $mediaService,
    ) {}

    public function getAll(): Collection
    {
        return Client::with(['user', 'profileMedia'])
          ->join('users', 'clients.user_id', '=', 'users.id')
          ->orderBy('users.name')
          ->select('clients.*')
          ->get();
    }

    public function findById(int $id): ?Client
    {
        return Client::with(['user', 'profileMedia'])->find($id);
    }

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

    public function update(array $data, int $id)
    {
        $client = Client::with(['profileMedia'])->findOrFail($id);

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

            $data['profile_media_id'] = $media->id;

            unset($data['avatar']);
        }

        $client->update($data);

        return $client->fresh(['user', 'profileMedia']);
    }

    public function delete(int $id): bool
    {
        $client = Client::findOrFail($id);

        return $client->delete();
    }

    //

    public function register(array $data): ?array
    {
        try {
            DB::beginTransaction();

            $user = User::where('email', data_get($data, 'email'))
                ->where('type', UserTypeEnum::CLIENT->value)
                ->where('code', data_get($data, 'code'))
                ->first();

            if (! $user) {
                throw new \Exception(__('messages.user_not_found_or_code_not_validated'));
            }

            if (! empty(data_get($data, 'name'))) {
                $user->name = data_get($data, 'name');
            }

            $user->phone = data_get($data, 'phone');

            $user->save();

            $client = Client::firstOrCreate(
                ['user_id' => $user->id], ['document' => data_get($data, 'document')]
            );

            if (! empty(data_get($data, 'document'))) {
                $client->document = data_get($data, 'document');

                $client->save();
            }

            $client->refresh();

            if (data_get($data, 'avatar') !== null && data_get($data, 'avatar') instanceof UploadedFile) {
                $client->load('profileMedia');

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

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

                $client->save();
            }

            $addressData = [
                'zip_code'       => data_get($data, 'zip_code'),
                'address'        => data_get($data, 'address'),
                'number'         => data_get($data, 'number'),
                'district'       => data_get($data, 'district'),
                'has_complement' => data_get($data, 'has_complement', false),
                'complement'     => data_get($data, 'complement'),
                'nickname'       => data_get($data, 'nickname'),
                'instructions'   => data_get($data, 'instructions'),
                'address_type'   => data_get($data, 'address_type', 'home'),
                'is_primary'     => true,
                'latitude'       => data_get($data, 'latitude'),
                'longitude'      => data_get($data, 'longitude'),
            ];

            if (! empty(data_get($data, 'state')) && ! empty(data_get($data, 'city'))) {
                $state = State::where('code', data_get($data, 'state'))->first();

                if ($state) {
                    $city = City::where('name', data_get($data, 'city'))->where('state_id', $state->id)->first();

                    $addressData['state_id'] = $state->id;
                    $addressData['city_id']  = $city?->id;
                }
            }

            Address::updateOrCreate(
                ['source' => 'client', 'source_id' => $client->id],
                $addressData
            );

            $this->pagarmeCustomerService->createCustomerForClient($client, $data);

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

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

                $user->save();
            }

            $result = $this->authService->loginWithEmail(
                email: $user->email,
                code: $user->code,
                type: UserTypeEnum::CLIENT->value,
            );

            DB::commit();

            return $result;
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error('Erro ao cadastrar cliente: '.$e->getMessage());

            throw $e;
        }
    }
}
