<?php

namespace App\Services;

use App\Models\City;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;

class AddressCityResolver
{
    public const SOURCE_SEED = 'seed';

    public const SOURCE_CUSTOMER = 'customer';

    public function resolve(
        ?int $cityId,
        ?string $customName,
        int $stateId,
        int $countryId,
        ?int $userId = null,
        string $source = self::SOURCE_CUSTOMER,
        ?float $cost = null,
        ?bool $status = null,
    ): City {
        if ($cityId) {
            $city = City::query()
                ->where('id', $cityId)
                ->where('state_id', $stateId)
                ->where('status', true)
                ->first();

            if (!$city) {
                throw new InvalidArgumentException('Selected city is invalid for this state.');
            }

            return $city;
        }

        $normalized = $this->normalizeName($customName ?? '');
        if ($normalized === '') {
            throw new InvalidArgumentException('City name is required.');
        }

        return DB::transaction(function () use ($normalized, $stateId, $countryId, $userId, $source, $cost, $status) {
            $existing = City::query()
                ->where('state_id', $stateId)
                ->whereRaw('LOWER(name) = ?', [mb_strtolower($normalized)])
                ->lockForUpdate()
                ->first();

            if ($existing) {
                $updates = [];
                if ($cost !== null) {
                    $updates['cost'] = $cost;
                }
                if ($status !== null) {
                    $updates['status'] = $status;
                }
                if ($updates !== []) {
                    $existing->update($updates);
                    if (array_key_exists('status', $updates)) {
                        Cache::forget("shipping:cities:{$stateId}");
                    }
                }

                return $existing->fresh();
            }

            $city = City::create([
                'name' => $normalized,
                'state_id' => $stateId,
                'country_id' => $countryId,
                'cost' => $cost ?? 0,
                'status' => $status ?? true,
                'source' => $source,
                'created_by_user_id' => $userId,
            ]);

            Cache::forget("shipping:cities:{$stateId}");

            return $city;
        });
    }

    public function normalizeName(?string $name): string
    {
        $name = strip_tags(trim((string) $name));
        $name = preg_replace('/\s+/u', ' ', $name) ?? '';

        if ($name === '') {
            return '';
        }

        return mb_convert_case($name, MB_CASE_TITLE, 'UTF-8');
    }
}
