<?php

namespace App\Synapse\Tools;

use App\Enum\Dsar\DsarStatus;
use App\Models\Dsar\Dsar;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

class SearchDsarByReferenceTool implements Tool
{
    public function description(): Stringable|string
    {
        return 'Search for a DSAR by reference number or by client name. '
             . 'Use this first when the email subject or body contains a DSAR reference (e.g. "DSAR-20260603-3B0EFD", "Ref: 100001") '
             . 'or a client name. A direct reference match is more reliable than institution name matching.';
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'reference'   => $schema->string()
                ->description('DSAR reference number to search for (e.g. "DSAR-20260603-3B0EFD"). Leave empty string if searching by name.')
                ->required(),
            'client_name' => $schema->string()
                ->description('Client full name or partial name to search for. Leave empty string if searching by reference.')
                ->required(),
        ];
    }

    public function handle(Request $request): Stringable|string
    {
        $reference  = trim($request['reference'] ?? '');
        $clientName = trim($request['client_name'] ?? '');

        if ($reference === '' && $clientName === '') {
            return json_encode(['error' => 'Provide at least a reference or client_name']);
        }

        $query = Dsar::withoutGlobalScopes()
            ->whereNotIn('status', DsarStatus::excludedFromOpen())
            ->with(['claim.client', 'institution']);

        if ($reference !== '') {
            $query->where(function ($q) use ($reference) {
                $q->where('reference', $reference)
                  ->orWhere('reference', 'like', "%{$reference}%")
                  ->orWhere('receiver_reference', $reference)
                  ->orWhere('receiver_reference', 'like', "%{$reference}%");
            });
        } elseif ($clientName !== '') {
            $query->whereHas('claim.client', function ($q) use ($clientName) {
                $parts = preg_split('/\s+/', $clientName, 2);
                if (count($parts) === 2) {
                    $q->where(function ($q2) use ($parts) {
                        $q2->where('name_first', 'like', "%{$parts[0]}%")
                           ->where('name_last', 'like', "%{$parts[1]}%");
                    })->orWhere(function ($q2) use ($parts) {
                        $q2->where('name_first', 'like', "%{$parts[1]}%")
                           ->where('name_last', 'like', "%{$parts[0]}%");
                    });
                } else {
                    $q->where('name_first', 'like', "%{$clientName}%")
                      ->orWhere('name_last', 'like', "%{$clientName}%");
                }
            });
        }

        $dsars = $query->orderByDesc('posted_at')->limit(10)->get();

        if ($dsars->isEmpty()) {
            return json_encode([
                'results' => [],
                'count'   => 0,
                'message' => 'No DSARs found matching that reference or client name.',
            ]);
        }

        $results = $dsars->map(fn (Dsar $dsar) => [
            'dsar_id'            => $dsar->id,
            'reference'          => $dsar->reference,
            'receiver_reference' => $dsar->receiver_reference,
            'status'             => $dsar->status,
            'institution_id'     => $dsar->institution_id,
            'institution_name'   => $dsar->institution?->display_name,
            'client_name'        => $dsar->claim?->client
                ? trim($dsar->claim->client->name_first . ' ' . $dsar->claim->client->name_last)
                : null,
            'posted_at'          => $dsar->posted_at?->toDateString(),
            'expected_at'        => $dsar->expected_at?->toDateString(),
        ]);

        return json_encode(['results' => $results, 'count' => $results->count()]);
    }
}
