<?php

namespace App\Filament\Resources\CustomerResource\Pages;

use App\Filament\Resources\CustomerResource;
use App\Filament\Support\StatusLookup;
use App\Models\Customers\Customer;
use App\Models\Lookups\Status;
use App\Models\Loyalty\CustomerLoyaltyBalance;
use App\Models\Returns\CreditNote;
use App\Models\Returns\ReturnDoc;
use App\Models\Sales\Invoice;
use App\Models\Sales\Transaction;
use App\Services\CurrentContext;
use Filament\Infolists\Components\RepeatableEntry;
use Filament\Infolists\Components\TextEntry;
use Filament\Resources\Pages\ViewRecord;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Tabs;
use Filament\Schemas\Components\Tabs\Tab;
use Filament\Schemas\Schema;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

/**
 * Ported from CustomerController::show() — the per-customer statement.
 *
 * Reproduces the same financial summary (including the PHP-computed average
 * payment delay, kept in PHP so the query stays portable across SQLite and
 * MySQL), the same four tabs (orders / payments / returns / credit notes), the
 * merged activity timeline, and the loyalty balance.
 */
class ViewCustomer extends ViewRecord
{
    protected static string $resource = CustomerResource::class;

    public function infolist(Schema $schema): Schema
    {
        return $schema->components([
            Section::make()->schema([
                TextEntry::make('business_name')->label('Customer'),
                TextEntry::make('phone'),
                TextEntry::make('nic')->label('NIC')->placeholder('—'),
                TextEntry::make('email')->placeholder('—'),
                TextEntry::make('city.name')->label('City')->placeholder('—'),
                TextEntry::make('assignedUser.name')->label('Assigned to')->placeholder('—'),
                TextEntry::make('is_active')
                    ->label('Status')
                    ->badge()
                    ->formatStateUsing(fn ($state): string => $state ? 'Active' : 'Inactive')
                    ->color(fn ($state): string => $state ? 'success' : 'gray'),
            ])->columns(3),

            Section::make('Financial summary')->schema([
                TextEntry::make('summary_outstanding')
                    ->label('Outstanding balance')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['outstanding_balance'])),
                TextEntry::make('summary_orders')
                    ->label('Total orders')
                    ->state(fn (Customer $record): string => (string) static::summaryFor($record)['total_orders']),
                TextEntry::make('summary_invoiced')
                    ->label('Total invoiced')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['total_invoiced'])),
                TextEntry::make('summary_paid')
                    ->label('Total paid')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['total_paid'])),
                TextEntry::make('summary_returns')
                    ->label('Total returns')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['total_returns'])),
                TextEntry::make('summary_credit_notes')
                    ->label('Credit notes')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['credit_notes'])),
                TextEntry::make('summary_credit_balance')
                    ->label('Credit balance')
                    ->state(fn (Customer $record): string => static::money(static::summaryFor($record)['credit_balance'])),
                TextEntry::make('summary_delay')
                    ->label('Avg. payment delay')
                    ->state(function (Customer $record): string {
                        $days = static::summaryFor($record)['avg_payment_delay_days'];

                        return $days === null ? '—' : $days.' days';
                    }),
                TextEntry::make('loyalty_points')
                    ->label('Loyalty points')
                    ->state(function (Customer $record): string {
                        $balance = CustomerLoyaltyBalance::with('tier')->where('customer_id', $record->id)->first();
                        if (! $balance) {
                            return '—';
                        }

                        return rtrim(rtrim(number_format((float) $balance->points_balance, 2), '0'), '.')
                            .($balance->tier ? ' ('.$balance->tier->name.')' : '');
                    }),
            ])->columns(3),

            Tabs::make('Activity')->tabs([
                Tab::make('Orders')->schema([
                    RepeatableEntry::make('invoices')
                        ->label('')
                        ->schema([
                            TextEntry::make('invoice_number')->label('Invoice'),
                            TextEntry::make('created_at')->date(),
                            TextEntry::make('net_total')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('paid_amount')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('balance')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('paymentStatus.name')
                                ->label('Payment')
                                ->badge()
                                ->color(fn (Invoice $record): string => StatusLookup::colorOf(Status::CTX_INVOICE_PAYMENT, $record->paymentStatus?->code ?? '')),
                        ])
                        ->columns(6)
                        ->columnSpanFull(),
                ]),

                Tab::make('Payments')->schema([
                    RepeatableEntry::make('transactions')
                        ->label('')
                        ->schema([
                            TextEntry::make('transaction_number')->label('Transaction'),
                            TextEntry::make('taken_on')->date(),
                            TextEntry::make('amount')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('used_amount')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('method.name')->label('Method')->placeholder('—'),
                            TextEntry::make('status.name')
                                ->label('Status')
                                ->badge()
                                ->placeholder('—')
                                ->color(fn (Transaction $record): string => StatusLookup::colorOf(Status::CTX_TRANSACTION, $record->status?->code ?? '')),
                        ])
                        ->columns(6)
                        ->columnSpanFull(),
                ]),

                Tab::make('Returns')->schema([
                    RepeatableEntry::make('returns')
                        ->label('')
                        ->schema([
                            TextEntry::make('return_number')->label('Return'),
                            TextEntry::make('created_at')->date(),
                            TextEntry::make('total')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('status.name')
                                ->label('Status')
                                ->badge()
                                ->placeholder('—')
                                ->color(fn (ReturnDoc $record): string => StatusLookup::colorOf(Status::CTX_RETURN, $record->status?->code ?? '')),
                        ])
                        ->columns(4)
                        ->columnSpanFull(),
                ]),

                Tab::make('Credit notes')->schema([
                    RepeatableEntry::make('creditNotes')
                        ->label('')
                        ->state(fn (Customer $record): array => CreditNote::where('customer_id', $record->id)
                            ->with('status:id,code,name,color')
                            ->orderByDesc('issued_at')
                            ->get()
                            ->map(fn (CreditNote $cn): array => [
                                'cn_number' => $cn->cn_number,
                                'amount' => (float) $cn->amount,
                                'status' => $cn->status?->name,
                                'status_color' => StatusLookup::colorOf(Status::CTX_CREDIT_NOTE, $cn->status?->code ?? ''),
                                'issued_at' => $cn->issued_at?->toDateString(),
                                'claimed_at' => $cn->claimed_at?->toDateString(),
                            ])
                            ->all())
                        ->schema([
                            TextEntry::make('cn_number')->label('Credit note'),
                            TextEntry::make('amount')->money(fn () => app(CurrentContext::class)->currencyCode()),
                            TextEntry::make('status')
                                ->badge()
                                ->placeholder('—')
                                ->color(fn ($record) => is_array($record) ? ($record['status_color'] ?? 'gray') : 'gray'),
                            TextEntry::make('issued_at')->label('Issued')->placeholder('—'),
                            TextEntry::make('claimed_at')->label('Claimed')->placeholder('—'),
                        ])
                        ->columns(5)
                        ->columnSpanFull(),
                ]),

                Tab::make('Timeline')->schema([
                    RepeatableEntry::make('timeline')
                        ->label('')
                        ->state(fn (Customer $record): array => static::timelineFor($record))
                        ->schema([
                            TextEntry::make('date')->label('Date'),
                            TextEntry::make('type')->badge(),
                            TextEntry::make('label')->label('Event'),
                            TextEntry::make('amount')->money(fn () => app(CurrentContext::class)->currencyCode()),
                        ])
                        ->columns(4)
                        ->columnSpanFull(),
                ]),
            ])->columnSpanFull(),
        ]);
    }

    protected static function money(float $value): string
    {
        return 'Rs. '.number_format($value, 2);
    }

    /**
     * Ported verbatim from CustomerController::show()'s $summary block.
     * Memoized per request so the eight infolist entries don't re-run it.
     *
     * @return array<string, float|int|null>
     */
    public static function summaryFor(Customer $customer): array
    {
        static $cache = [];

        if (isset($cache[$customer->id])) {
            return $cache[$customer->id];
        }

        $invoiceSummary = Invoice::where('customer_id', $customer->id)
            ->selectRaw('COUNT(*) as total_count, SUM(net_total) as total_invoiced, SUM(paid_amount) as total_paid, SUM(balance) as total_outstanding')
            ->first();

        $returnTotal = ReturnDoc::where('customer_id', $customer->id)->sum('total');

        $creditNoteTotal = CreditNote::where('customer_id', $customer->id)
            ->whereNull('deleted_at')
            ->sum('amount');

        // Average payment delay in days (invoices that have been paid). Computed
        // in PHP rather than via JULIANDAY/DATEDIFF so the query stays portable
        // across the SQLite (testing) and MySQL (production) drivers.
        $delays = DB::table('invoices')
            ->where('invoices.customer_id', $customer->id)
            ->whereNotNull('paid_amount')
            ->where('paid_amount', '>', 0)
            ->join('transaction_claims', 'invoices.id', '=', 'transaction_claims.invoice_id')
            ->join('transactions', 'transaction_claims.transaction_id', '=', 'transactions.id')
            ->select('invoices.created_at as invoiced_at', 'transactions.taken_on as paid_at')
            ->get();

        $avgDelay = $delays->isEmpty()
            ? null
            : $delays->avg(fn ($row) => (strtotime($row->paid_at) - strtotime($row->invoiced_at)) / 86400);

        return $cache[$customer->id] = [
            'outstanding_balance' => (float) ($invoiceSummary->total_outstanding ?? 0),
            'total_orders' => (int) ($invoiceSummary->total_count ?? 0),
            'total_invoiced' => (float) ($invoiceSummary->total_invoiced ?? 0),
            'total_paid' => (float) ($invoiceSummary->total_paid ?? 0),
            'total_returns' => (float) $returnTotal,
            'credit_notes' => (float) $creditNoteTotal,
            'credit_balance' => (float) ($customer->creditBalance?->balance ?? 0),
            'avg_payment_delay_days' => $avgDelay !== null ? round((float) $avgDelay, 1) : null,
        ];
    }

    /**
     * The merged, date-descending activity timeline from the source's show().
     *
     * @return array<int, array<string, mixed>>
     */
    public static function timelineFor(Customer $customer): array
    {
        $timeline = collect();

        foreach (Invoice::where('customer_id', $customer->id)->with('paymentStatus:id,code')->get() as $inv) {
            $timeline->push([
                'type' => 'invoice',
                'date' => $inv->created_at,
                'label' => "Invoice {$inv->invoice_number} created",
                'amount' => (float) $inv->net_total,
                'reference' => $inv->invoice_number,
                'status' => $inv->paymentStatus?->code,
            ]);
        }

        foreach (Transaction::where('customer_id', $customer->id)->with('method:id,name')->get() as $txn) {
            $timeline->push([
                'type' => 'payment',
                'date' => $txn->taken_on,
                'label' => "Payment {$txn->transaction_number} received",
                'amount' => (float) $txn->amount,
                'reference' => $txn->transaction_number,
                'method' => $txn->method?->name,
            ]);
        }

        foreach (ReturnDoc::where('customer_id', $customer->id)->get() as $ret) {
            $timeline->push([
                'type' => 'return',
                'date' => $ret->created_at,
                'label' => "Return {$ret->return_number}",
                'amount' => (float) $ret->total,
                'reference' => $ret->return_number,
            ]);
        }

        foreach (CreditNote::where('customer_id', $customer->id)->whereNull('deleted_at')->with('status:id,code')->get() as $cn) {
            $timeline->push([
                'type' => 'credit_note',
                'date' => $cn->issued_at,
                'label' => "Credit Note {$cn->cn_number} issued",
                'amount' => (float) $cn->amount,
                'reference' => $cn->cn_number,
                'status' => $cn->status?->code,
            ]);
        }

        return $timeline
            ->sortByDesc('date')
            ->values()
            ->map(fn (array $row): array => [
                ...$row,
                'date' => $row['date'] ? Carbon::parse($row['date'])->toDateString() : null,
            ])
            ->all();
    }
}
