<?php

namespace App\Repositories;

use AllowDynamicProperties;
use App\Models\Role;
use App\Models\User;
use App\Models\UserMeta;
use Illuminate\Auth\Events\Registered;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;

#[AllowDynamicProperties]
class UserRepository
{
    public function __construct(User $user)
    {
        $this->model = $user;
    }

    public function create(array $data)
    {
        try {
            $user = new User([
                'email' => $data['email'],
                'first_name' => $data['first_name'],
                'last_name' => $data['last_name'],
                'password' => bcrypt($data['password']),
            ]);

            $user->email_verified_at = now();

            $user->save();

            $user->roles()->attach(Role::where('id', $data['roles'])->first());

            if (isset($data['phone_number']) || isset($data['company_name']) || isset($data['billing_address']) || isset($data['billing_city']) || isset($data['billing_state']) || isset($data['billing_zip']) || isset($data['billing_country'])) {
                $user->billingAddress()->create([
                    'first_name' => $data['first_name'],
                    'last_name' => $data['last_name'],
                    'phone_number' => $data['phone_number'] ?? null,
                    'company_name' => $data['company_name'] ?? null,
                    'address' => $data['billing_address'] ?? null,
                    'city' => $data['billing_city'] ?? null,
                    'state_id' => $data['billing_state'] ?? null,
                    'zip' => $data['billing_zip'] ?? null,
                    'country_id' => $data['billing_country'] ?? null,
                    'email' => $data['email'],
                ]);
            }

            foreach ($data['reg_fields'] ?? [] as $key => $value) {
                if ($value !== null && $value !== '') {
                    $user->meta()->create(['key' => $key, 'value' => $value]);
                }
            }

            event(new Registered($user));

            return $user;

        } catch (QueryException $e) {
            throw $e;
        }

    }


    public function find($id)
    {
        try {
            return $this->model->findOrFail($id);
        } catch (ModelNotFoundException $ex) {
            throw $ex;
        }
    }

    public function update(array $data, $id)
    {
        $user = $this->find($id);

        try {
            $user->update([
                'email' => $data['email'],
                'first_name' => $data['first_name'],
                'last_name' => $data['last_name'],
                'password' => isset($data['password']) ? bcrypt($data['password']) : $user->password,
            ]);

            // if request is coming from frontend.
            if (isset($data['roles'])) {
                $user->roles()->detach();
                $user->roles()->attach(Role::where('id', $data['roles'])->first());
            }

            // Normalize empty strings to null so ?? fallback works correctly
            $billingInput = [
                'phone_number' => ($data['phone_number'] ?? '') !== '' ? $data['phone_number'] : null,
                'company_name' => ($data['company_name'] ?? '') !== '' ? $data['company_name'] : null,
                'address'      => ($data['billing_address'] ?? '') !== '' ? $data['billing_address'] : null,
                'city'         => ($data['billing_city'] ?? '') !== '' ? $data['billing_city'] : null,
                'state_id'     => ($data['billing_state'] ?? '') !== '' ? $data['billing_state'] : null,
                'zip'          => ($data['billing_zip'] ?? '') !== '' ? $data['billing_zip'] : null,
                'country_id'   => ($data['billing_country'] ?? '') !== '' ? $data['billing_country'] : null,
            ];

            // Only touch billing_addresses if at least one field has a real value
            if (array_filter($billingInput) || $user->billingAddress) {
                $existing = $user->billingAddress;
                $user->billingAddress()->updateOrCreate(
                    ['user_id' => $user->id],
                    [
                        'first_name'   => $data['first_name'],
                        'last_name'    => $data['last_name'],
                        'email'        => $data['email'],
                        'phone_number' => $billingInput['phone_number'] ?? $existing?->phone_number,
                        'company_name' => $billingInput['company_name'] ?? $existing?->company_name,
                        'address'      => $billingInput['address'] ?? $existing?->address,
                        'city'         => $billingInput['city'] ?? $existing?->city,
                        'state_id'     => $billingInput['state_id'] ?? $existing?->state_id,
                        'zip'          => $billingInput['zip'] ?? $existing?->zip,
                        'country_id'   => $billingInput['country_id'] ?? $existing?->country_id,
                    ]
                );
            }

            foreach ($data['reg_fields'] ?? [] as $key => $value) {
                $user->meta()->updateOrCreate(['key' => $key], ['value' => $value]);
            }

            return $user;

        } catch (\Exception $exc) {
            throw $exc;
        }
    }

    public function delete($id)
    {
        $user = $this->find($id);

        return $user->delete();
    }

    public function deleteUsers(array $userIds)
    {
        return $this->model::whereIn('id', $userIds)->delete();
    }

    public function paginate()
    {

    }

    public function filter($searchTerm = null, $verification_status = null, $role = null, $perPage = 10)
    {
        $query = $this->model::latest('id');

        if ($searchTerm) {
            $query->where(function ($q) use ($searchTerm) {
                $q->where('first_name', 'LIKE', '%' . $searchTerm . '%')
                    ->orWhere('last_name', 'LIKE', '%' . $searchTerm . '%')
                    ->orWhere('email', 'LIKE', '%' . $searchTerm . '%');
            });
        }

        if ($verification_status !== null) {
            if ($verification_status == 'yes') {
                $query->whereNotNull('email_verified_at');
            } else {
                $query->whereNull('email_verified_at');
            }
        }

        if ($role) {
            $query->whereHas('roles', fn($q) => $q->where('id', $role));
        }

        return $query->paginate($perPage);
    }

    public function getAll($perPage = 15)
    {
        return $this->model::latest('id')->paginate($perPage);
    }

}
