<?php

namespace App\Ai\Tools;

use App\Models\Client;
use App\Models\CustomerPaymentCollection;
use App\Models\SalesMaster;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

class CustomerTool implements Tool
{
    public function description(): Stringable|string
    {
        return 'Get customer info: search by name, total due, last sales invoice, total payment, date-wise payments.';
    }

    public function handle(Request $request): Stringable|string
    {
        $customerSearch = $request['customer'] ?? null;
        $metric = $request['metric'] ?? null; // due, last_invoice, total_payment, date_wise_payment
        $date = $request['date'] ?? null;
        $from = $request['from'] ?? null;
        $to = $request['to'] ?? null;

        $query = Client::query()->where('status', 1);

        if (! empty($customerSearch)) {
            $query->where(function ($q) use ($customerSearch) {
                $q->where('name', 'like', '%'.$customerSearch.'%')
                    ->orWhere('code', 'like', '%'.$customerSearch.'%')
                    ->orWhere('number', 'like', '%'.$customerSearch.'%');
            });
        }

        $customers = $query->orderBy('name')->limit(20)->get();

        if ($customers->isEmpty()) {
            return 'No customers found.';
        }

        $lines = [];
        $total = $customers->count();

        foreach ($customers as $index => $client) {
            $customerId = $client->id;

            // Total due: opening + sales - returns - payments
            $opening = (float) DB::table('customer_opening_details as cod')
                ->join('customer_openings as co', 'cod.customer_opening_id', '=', 'co.id')
                ->where('co.client_id', $customerId)
                ->sum('cod.opening_balance');

            $sales = (float) SalesMaster::where('client_id', $customerId)->sum('grand_total');
            $returns = (float) DB::table('sales_return_masters as srm')
                ->join('sales_return_details as srd', 'srd.sales_return_master_id', '=', 'srm.id')
                ->where('srm.customer_id', $customerId)
                ->sum('srd.total');
            $payments = (float) CustomerPaymentCollection::where('customer_id', $customerId)->sum('payment');

            $totalDue = $opening + $sales - $returns - $payments;

            // Last sales invoice
            $lastInvoice = SalesMaster::where('client_id', $customerId)
                ->orderByDesc('created_at')
                ->first(['id', 'invoice_no', 'grand_total', 'created_at']);

            // Total payment (all time)
            $totalPayment = $payments;

            // Current pay = payment for last invoice (if any)
            $currentPay = $lastInvoice
                ? (float) CustomerPaymentCollection::where('invoice_id', $lastInvoice->id)->sum('payment')
                : 0;

            // Single-metric response
            if (! empty($metric) && $metric !== 'date_wise_payment') {
                switch ($metric) {
                    case 'due':
                        return $client->name.': Total due '.$totalDue;
                    case 'last_invoice':
                        if ($lastInvoice) {
                            return $client->name.': Last invoice '.$lastInvoice->invoice_no.' | '.$lastInvoice->grand_total.' | '.Carbon::parse($lastInvoice->created_at)->toDateString();
                        }

                        return $client->name.': No invoice found.';
                    case 'total_payment':
                        return $client->name.': Total paid '.$totalPayment;
                    case 'current_pay':
                        return $client->name.': Current pay (last invoice) '.$currentPay;
                }
            }

            if ($metric === 'date_wise_payment') {
                $payQuery = CustomerPaymentCollection::where('customer_id', $customerId)
                    ->selectRaw('DATE(date) as pay_date, SUM(payment) as total')
                    ->groupBy(DB::raw('DATE(date)'))
                    ->orderByDesc('pay_date')
                    ->limit(30);

                if (! empty($date)) {
                    try {
                        $d = Carbon::parse($date)->toDateString();
                        $payQuery->whereDate('date', $d);
                    } catch (\Throwable $e) {
                    }
                }
                if (! empty($from) || ! empty($to)) {
                    try {
                        if ($from) {
                            $payQuery->where('date', '>=', Carbon::parse($from)->startOfDay());
                        }
                        if ($to) {
                            $payQuery->where('date', '<=', Carbon::parse($to)->endOfDay());
                        }
                    } catch (\Throwable $e) {
                    }
                }

                $dateWise = $payQuery->get();
                if ($dateWise->isEmpty()) {
                    $lines[] = $client->name.': No payments in range.';
                } else {
                    $lines[] = $client->name.':';
                    foreach ($dateWise as $row) {
                        $lines[] = '  '.$row->pay_date.' | '.(float) $row->total;
                    }
                }
                continue;
            }

            $lines[] = 'Customer: '.$client->name;
            $lines[] = 'Total due: '.$totalDue;
            $lines[] = 'Total paid: '.$totalPayment;
            if ($lastInvoice) {
                $lines[] = 'Last invoice: '.$lastInvoice->invoice_no.' | '.$lastInvoice->grand_total.' | '.Carbon::parse($lastInvoice->created_at)->toDateString();
                $lines[] = 'Current pay (last invoice): '.$currentPay;
            } else {
                $lines[] = 'Last invoice: none';
            }
            if ($index < $total - 1) {
                $lines[] = '---';
            }
        }

        return implode("\n", $lines);
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'customer' => $schema->string()->nullable()->description('Search customer by name, code, or number (partial match)'),
            'metric' => $schema->string()->nullable()->description('Focus: due, last_invoice, total_payment, current_pay, date_wise_payment'),
            'date' => $schema->string()->nullable()->description('Filter date-wise payments by single date'),
            'from' => $schema->string()->nullable()->description('Filter date-wise payments from date'),
            'to' => $schema->string()->nullable()->description('Filter date-wise payments to date'),
        ];
    }
}
