<?php

namespace App\Filament\Resources;

use App\Filament\Exports\TillExporter;
use App\Filament\Resources\Concerns\AssertsBranchAccess;
use App\Filament\Resources\Concerns\HasModulePermissions;
use App\Filament\Resources\Concerns\HasStandardTableFeatures;
use App\Filament\Resources\TillResource\Pages\EditTill;
use App\Filament\Resources\TillResource\Pages\ListTills;
use App\Filament\Support\RelationSelect;
use App\Models\Sales\Till;
use App\Services\AuditLog;
use App\Services\CurrentContext;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Filters\Filter;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Filters\TernaryFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * Ported from App\Http\Controllers\Isms\TillController (docs/migration-plan.md
 * Phase 5). Plain CRUD — every route on the source controller is gated by
 * `pos.access` (not a `tills.*` module of its own), so `$permissionModuleKey`
 * is `pos` and create/edit/delete all resolve to `pos.access` via the
 * overrides below rather than the trait's default `pos.create`/`.edit`/
 * `.delete` — those verbs do not exist in the catalog for the `pos` module
 * (its actions are access/checkout/discount only), so the trait's defaults
 * would deny every till mutation outright.
 */
class TillResource extends Resource
{
    use AssertsBranchAccess;
    use HasModulePermissions;
    use HasStandardTableFeatures;

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

    protected static string $permissionModuleKey = 'pos';

    protected static string $exporter = TillExporter::class;

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

    protected static string|\UnitEnum|null $navigationGroup = 'Point of Sale';

    protected static ?string $navigationLabel = 'Tills';

    protected static ?int $navigationSort = 10;

    /**
     * Till creation is restricted to the central/master panel
     * (TenantResource -> TillsRelationManager). Tenants can view/edit
     * existing tills but cannot create new ones.
     */
    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        return static::hasModulePermission('access');
    }

    public static function canDelete(Model $record): bool
    {
        return static::hasModulePermission('access');
    }

    public static function canDeleteAny(): bool
    {
        return static::hasModulePermission('access');
    }

    /**
     * Same reasoning as the CRUD overrides above: the `pos` module's actions are
     * access/checkout/discount only, so there is no `pos.export` to require —
     * the till list is configuration rather than trading data, and `pos.access`
     * is the gate the source app puts on every till route.
     */
    public static function canExport(): bool
    {
        return static::hasModulePermission('access');
    }

    public static function form(Schema $schema): Schema
    {
        return $schema->components([
            Section::make()->schema([
                TextInput::make('identifier')
                    ->label('Identifier')
                    ->disabled()
                    ->dehydrated(false)
                    ->placeholder('Generated automatically')
                    ->helperText('Assigned automatically when the till is created.'),
                TextInput::make('name')->required()->maxLength(100),
                RelationSelect::make(
                    name: 'branch_id',
                    relationship: 'branch',
                    titleAttribute: 'name',
                    modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                )->label('Branch'),
                Toggle::make('is_active')->default(true),
            ]),
        ]);
    }

    public static function table(Table $table): Table
    {
        return static::standardTableDefaults($table)
            ->recordUrl(static::standardRecordUrl())
            ->emptyStateHeading('No tills yet')
            ->emptyStateDescription('A till is where the cashier works.')
            ->columns([
                TextColumn::make('identifier')->searchable()->sortable(),
                TextColumn::make('name')->searchable()->sortable(),
                TextColumn::make('branch.name')->placeholder('—'),
                IconColumn::make('is_active')->boolean(),
            ])
            // Matches TillController::index()'s orderByDesc('is_active')->orderBy('name').
            ->defaultSort('is_active', 'desc')
            ->filters([
                Filter::make('identifier')
                    ->schema([TextInput::make('value')->label('Identifier')])
                    ->query(fn (Builder $query, array $data): Builder => $query->when(
                        $data['value'] ?? null,
                        fn (Builder $q, $value) => $q->where('identifier', 'like', "%{$value}%"),
                    )),
                SelectFilter::make('branch_id')->label('Branch')->relationship('branch', 'name'),
                TernaryFilter::make('is_active')->label('Active'),
            ])
            ->filtersLayout(FiltersLayout::AboveContentCollapsible)
            ->filtersFormColumns(2)
            ->headerActions(static::standardExportActions())
            ->toolbarActions(static::standardExportBulkActions())
            ->recordActions([
                EditAction::make(),
                // TillController::destroy() records the audit entry *before*
                // the delete, so the row is still readable — ->before() is the
                // equivalent hook.
                DeleteAction::make()
                    ->before(function (Till $record): void {
                        AuditLog::record('till.deleted', $record, [
                            'name' => $record->name,
                            'description' => 'Deleted till "'.$record->name.'".',
                        ]);
                    }),
            ]);
    }

    /**
     * Till master now mirrors POS visibility: users with no explicit
     * `user_till_access` rows (including new tenants after a master-created
     * till) see every branch-accessible till, so master tills appear
     * immediately. Once a user has explicit till assignments, the list is
     * filtered to those tills only — preserving per-cashier restriction.
     * Full admins (null) and central context bypass filtering entirely.
     * Branch filtering is still applied via the model's global BranchScope.
     */
    public static function getEloquentQuery(): Builder
    {
        $query = parent::getEloquentQuery();

        $accessible = app(CurrentContext::class)->accessibleTillIds();

        // Null = full admin (unrestricted) or empty = no explicit restriction yet
        // → show every branch-accessible till so master-created tills are visible.
        if ($accessible === null || $accessible->isEmpty()) {
            return $query;
        }

        return $query->whereIn('tills.id', $accessible);
    }

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