<?php

namespace App\Support\CostOfSale;

use App\Models\ClientDomain;
use App\Models\ClientProduct;
use App\Models\Order;
use App\Models\Product;
use App\Models\Tld;
use Illuminate\Database\Eloquent\Model;

// PRC-816 — Cost-of-sale bağ tipleri whitelist'i + etiket + arama.
// Kısa key ↔ model sınıfı; kullanıcı girdisi DAİMA buradan doğrulanır.
class LinkableResolver
{
    /** Kısa key → model sınıfı (fully-qualified, morph type olarak saklanır). */
    public const TYPES = [
        'order' => Order::class,
        'service' => ClientProduct::class,
        'domain' => ClientDomain::class,
        'product' => Product::class,
        'tld' => Tld::class,
    ];

    public static function classForKey(?string $key): ?string
    {
        return $key ? (self::TYPES[$key] ?? null) : null;
    }

    public static function keyForClass(?string $class): ?string
    {
        return $class ? (array_flip(self::TYPES)[$class] ?? null) : null;
    }

    /** Girdiyi doğrula: type whitelist'te + id o tabloda mevcut. */
    public static function isValid(string $key, $id): bool
    {
        $class = self::classForKey($key);

        return $class ? $class::query()->whereKey($id)->exists() : false;
    }

    /** Bağlı model için insan-okur etiket. */
    public static function label(?Model $model): string
    {
        if (! $model) {
            return '—';
        }

        return match (true) {
            $model instanceof Order => 'Order #'.$model->id.self::clientSuffix($model->client),
            $model instanceof ClientProduct => '#'.$model->id.' '.trim(($model->product?->name ?? '').($model->domain ? ' ('.$model->domain.')' : '')),
            $model instanceof ClientDomain => (string) $model->domain,
            $model instanceof Product => (string) $model->name,
            $model instanceof Tld => (string) $model->tld,
            default => class_basename($model).' #'.$model->id,
        };
    }

    private static function clientSuffix(?Model $client): string
    {
        if (! $client) {
            return '';
        }
        $name = trim(($client->first_name ?? '').' '.($client->last_name ?? ''));
        if (! empty($client->company_name)) {
            $name = $name !== '' ? $name.' — '.$client->company_name : $client->company_name;
        }

        return $name !== '' ? ' — '.$name : '';
    }

    /** select2-ajax: type key + arama → [{id, text}]. */
    public static function search(string $key, string $q, int $limit = 20): array
    {
        $class = self::classForKey($key);
        if (! $class) {
            return [];
        }

        $query = $class::query()->limit($limit);
        $q = trim($q);

        switch ($key) {
            case 'order':
                if (is_numeric($q)) {
                    $query->where('id', (int) $q);
                } elseif ($q !== '') {
                    $query->whereHas('client', fn ($c) => $c
                        ->where('first_name', 'like', "%{$q}%")
                        ->orWhere('last_name', 'like', "%{$q}%")
                        ->orWhere('company_name', 'like', "%{$q}%"));
                }
                $query->with('client')->latest('id');
                break;

            case 'service':
                $query->where(function ($x) use ($q) {
                    $x->where('domain', 'like', "%{$q}%")
                        ->orWhereHas('product', fn ($p) => $p->where('name', 'like', "%{$q}%"));
                    if (is_numeric($q)) {
                        $x->orWhere('id', (int) $q);
                    }
                })->with('product')->latest('id');
                break;

            case 'domain':
                $query->where('domain', 'like', "%{$q}%")->latest('id');
                break;

            case 'product':
                if ($q !== '') {
                    $query->where('name', 'like', "%{$q}%");
                }
                $query->orderBy('name');
                break;

            case 'tld':
                if ($q !== '') {
                    $query->where('tld', 'like', "%{$q}%");
                }
                $query->orderBy('tld');
                break;
        }

        return $query->get()->map(fn (Model $m) => [
            'id' => $m->id,
            'text' => self::label($m),
        ])->all();
    }
}
