<?php

namespace App\Services\Booking;

use App\Models\Customer;
use App\Support\Tenant;

class CustomerService
{
    /**
     * Encuentra un cliente por (company_id, phone) o lo crea con los datos provistos.
     * No actualiza datos existentes salvo que se pase $forceUpdate=true.
     */
    public function findOrCreate(array $data, bool $forceUpdate = false): Customer
    {
        $companyId = $data['company_id'] ?? Tenant::id();
        $phone = $this->normalizePhone($data['phone']);
        $email = $this->normalizeEmail($data['email'] ?? null);

        $customer = $this->findExisting($companyId, $phone, $email);

        if ($customer) {
            $updates = [
                'phone' => $phone,
                'email' => $email,
            ];

            foreach (['first_name', 'last_name'] as $field) {
                if ($forceUpdate || blank($customer->{$field})) {
                    $updates[$field] = $data[$field] ?? null;
                }
            }

            if ($forceUpdate || blank($customer->email)) {
                $updates['email'] = $email;
            }

            if ($forceUpdate || blank($customer->phone) || $this->normalizePhone($customer->phone) !== $phone) {
                $updates['phone'] = $phone;
            }

            $updates = array_filter($updates, fn ($value) => filled($value));

            if ($updates) {
                $customer->forceFill($updates)->save();
            }

            return $customer;
        }

        return Customer::create([
            'company_id' => $companyId,
            'first_name' => $data['first_name'] ?? 'Cliente',
            'last_name'  => $data['last_name'] ?? null,
            'email'      => $email,
            'phone'      => $phone,
            'is_active'  => true,
        ]);
    }

    public function normalizePhone(string $phone): string
    {
        $digits = preg_replace('/\D+/', '', $phone);

        if ($digits === '') {
            return '';
        }

        return '+'.$digits;
    }

    public function normalizeEmail(?string $email): ?string
    {
        $email = strtolower(trim((string) $email));

        return $email !== '' ? $email : null;
    }

    protected function findExisting(int $companyId, string $phone, ?string $email): ?Customer
    {
        $lastTenDigits = $this->lastTenDigits($phone);

        return Customer::query()
            ->where('company_id', $companyId)
            ->where(function ($query) use ($phone, $email, $lastTenDigits) {
                $query->where('phone', $phone);

                if ($email) {
                    $query->orWhereRaw('LOWER(email) = ?', [$email]);
                }

                if ($lastTenDigits) {
                    $query->orWhere('phone', 'like', '%'.$lastTenDigits);
                    $query->orWhere('phone', 'like', '%'.$lastTenDigits.'%');
                }
            })
            ->orderByDesc('last_booking_at')
            ->orderByDesc('id')
            ->first();
    }

    protected function lastTenDigits(string $phone): ?string
    {
        $digits = preg_replace('/\D+/', '', $phone);

        return strlen($digits) >= 10 ? substr($digits, -10) : null;
    }
}
