<?php

namespace App\Filament\Resources;

use App\Filament\Exports\CustomerLoyaltyBalanceExporter;
use App\Filament\Resources\Concerns\HasModulePermissions;
use App\Filament\Resources\Concerns\HasStandardTableFeatures;
use App\Filament\Resources\LoyaltyBalanceResource\Pages\ListLoyaltyBalances;
use App\Filament\Support\Perm;
use App\Models\Loyalty\CustomerLoyaltyBalance;
use App\Services\LoyaltyService;
use Filament\Actions\Action;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * The customer points balances half of LoyaltyProgramController::index()
 * (docs/migration-plan.md Phase 7), plus its `adjust` action
 * (POST customers/{customer}/loyalty/adjust, gated by isms_loyalty.manage).
 *
 * Read-only: balances are only ever written by LoyaltyService (earn/redeem/
 * reverse) or the manual adjustment below, never created or deleted by hand.
 * The source renders these on the same screen as the programs; Filament gives
 * each its own listing, which is the same access pattern a tabbed page
 * provides in the Inertia SPA.
 */
class LoyaltyBalanceResource extends Resource
{
    use HasModulePermissions;
    use HasStandardTableFeatures;

    protected static ?string $model = CustomerLoyaltyBalance::class;

    protected static string $permissionModuleKey = 'isms_loyalty';

    protected static string $exporter = CustomerLoyaltyBalanceExporter::class;

    protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedStar;

    protected static string|\UnitEnum|null $navigationGroup = 'Promotions & Loyalty';

    protected static ?string $navigationLabel = 'Loyalty Balances';

    protected static ?int $navigationSort = 20;

    protected static ?string $slug = 'loyalty-balances';

    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        return false;
    }

    public static function canDelete(Model $record): bool
    {
        return false;
    }

    public static function canDeleteAny(): bool
    {
        return false;
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with(['customer:id,business_name,phone', 'tier:id,name,color']);
    }

    public static function table(Table $table): Table
    {
        return static::standardTableDefaults($table)
            ->recordUrl(static::standardRecordUrl())
            ->emptyStateHeading('No loyalty balances yet')
            ->emptyStateDescription('Customers earn points once a loyalty program is active.')
            ->columns([
                TextColumn::make('customer.business_name')->label('Customer')->searchable()->placeholder('—'),
                TextColumn::make('customer.phone')->label('Phone')->placeholder('—'),
                TextColumn::make('points_balance')->label('Points')->sortable(),
                TextColumn::make('lifetime_points')->label('Lifetime')->sortable(),
                TextColumn::make('tier.name')->label('Tier')->badge()->placeholder('—'),
            ])
            // Matches the source's orderByDesc('points_balance').
            ->defaultSort('points_balance', 'desc')
            ->filters([
                Filter::make('customer')
                    ->schema([TextInput::make('value')->label('Customer')])
                    ->query(fn (Builder $query, array $data): Builder => $query->when(
                        $data['value'] ?? null,
                        fn (Builder $q, $value) => $q->whereHas('customer', fn ($qq) => $qq->where('business_name', 'like', "%{$value}%")),
                    )),
                Filter::make('points_balance')
                    ->schema([
                        TextInput::make('from')->label('Points from')->numeric(),
                        TextInput::make('to')->label('Points to')->numeric(),
                    ])
                    ->query(fn (Builder $query, array $data): Builder => $query
                        ->when($data['from'] ?? null, fn (Builder $q, $v) => $q->where('points_balance', '>=', $v))
                        ->when($data['to'] ?? null, fn (Builder $q, $v) => $q->where('points_balance', '<=', $v))),
                SelectFilter::make('tier_id')->label('Tier')->relationship('tier', 'name'),
            ])
            ->filtersLayout(FiltersLayout::AboveContentCollapsible)
            ->filtersFormColumns(2)
            ->headerActions(static::standardExportActions())
            ->toolbarActions(static::standardExportBulkActions())
            ->recordActions([
                Action::make('adjust')
                    ->label('Adjust points')
                    ->visible(fn (): bool => Perm::can('isms_loyalty', 'manage'))
                    ->schema([
                        TextInput::make('points')
                            ->numeric()
                            ->required()
                            ->helperText('Negative to deduct.'),
                        TextInput::make('description')->required()->maxLength(255),
                    ])
                    ->action(function (CustomerLoyaltyBalance $record, array $data): void {
                        if (! $record->customer) {
                            Notification::make()->title('This balance has no customer attached.')->danger()->send();

                            return;
                        }

                        app(LoyaltyService::class)->adjust(
                            $record->customer,
                            (float) $data['points'],
                            $data['description'],
                        );

                        Notification::make()->title('Loyalty points adjusted.')->success()->send();
                    }),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => ListLoyaltyBalances::route('/'),
        ];
    }
}
