<?php

namespace App\Filament\Resources;

use App\Filament\Clusters\Inventory\InventoryCluster;
use App\Filament\Resources\InventoryItemResource\Pages;
use App\Models\InventoryItem;
use App\Models\Tenant;
use App\Services\Inventory\DependencyQueryService;
use App\Services\Inventory\DependencyTargets\DependencyTargetResolver;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Badges\TagBadgeRenderer;
use App\Support\Enums\RelationshipType;
use App\Support\Inventory\InventoryPolicyTypeMeta;
use BackedEnum;
use Filament\Actions;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Components\ViewEntry;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use UnitEnum;

class InventoryItemResource extends Resource
{
    protected static ?string $model = InventoryItem::class;

    protected static ?string $cluster = InventoryCluster::class;

    protected static ?int $navigationSort = 1;

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-rectangle-stack';

    protected static string|UnitEnum|null $navigationGroup = 'Inventory';

    public static function form(Schema $schema): Schema
    {
        return $schema;
    }

    public static function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Section::make('Inventory Item')
                    ->schema([
                        TextEntry::make('display_name')->label('Name'),
                        TextEntry::make('policy_type')
                            ->label('Type')
                            ->badge()
                            ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyType))
                            ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyType)),
                        TextEntry::make('category')
                            ->badge()
                            ->state(fn (InventoryItem $record): ?string => $record->category
                                ?: (static::typeMeta($record->policy_type)['category'] ?? null))
                            ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyCategory))
                            ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyCategory)),
                        TextEntry::make('platform')
                            ->badge()
                            ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::Platform))
                            ->color(TagBadgeRenderer::color(TagBadgeDomain::Platform)),
                        TextEntry::make('external_id')->label('External ID'),
                        TextEntry::make('last_seen_at')->label('Last seen')->dateTime(),
                        TextEntry::make('last_seen_run_id')
                            ->label('Last sync run')
                            ->url(function (InventoryItem $record): ?string {
                                if (! $record->last_seen_run_id) {
                                    return null;
                                }

                                return InventorySyncRunResource::getUrl('view', ['record' => $record->last_seen_run_id], tenant: Tenant::current());
                            })
                            ->openUrlInNewTab(),
                        TextEntry::make('support_restore')
                            ->label('Restore')
                            ->badge()
                            ->state(fn (InventoryItem $record): string => static::typeMeta($record->policy_type)['restore'] ?? 'enabled')
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::PolicyRestoreMode))
                            ->color(BadgeRenderer::color(BadgeDomain::PolicyRestoreMode))
                            ->icon(BadgeRenderer::icon(BadgeDomain::PolicyRestoreMode))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::PolicyRestoreMode)),
                        TextEntry::make('support_risk')
                            ->label('Risk')
                            ->badge()
                            ->state(fn (InventoryItem $record): string => static::typeMeta($record->policy_type)['risk'] ?? 'normal')
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::PolicyRisk))
                            ->color(BadgeRenderer::color(BadgeDomain::PolicyRisk))
                            ->icon(BadgeRenderer::icon(BadgeDomain::PolicyRisk))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::PolicyRisk)),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Dependencies')
                    ->schema([
                        ViewEntry::make('dependencies')
                            ->label('')
                            ->view('filament.components.dependency-edges')
                            ->state(function (InventoryItem $record) {
                                $direction = request()->query('direction', 'all');
                                $relationshipType = request()->query('relationship_type', 'all');
                                $relationshipType = is_string($relationshipType) ? $relationshipType : 'all';

                                $relationshipType = $relationshipType === 'all'
                                    ? null
                                    : RelationshipType::tryFrom($relationshipType)?->value;

                                $service = app(DependencyQueryService::class);
                                $resolver = app(DependencyTargetResolver::class);
                                $tenant = Tenant::current();

                                $edges = collect();
                                if ($direction === 'inbound' || $direction === 'all') {
                                    $edges = $edges->merge($service->getInboundEdges($record, $relationshipType));
                                }
                                if ($direction === 'outbound' || $direction === 'all') {
                                    $edges = $edges->merge($service->getOutboundEdges($record, $relationshipType));
                                }

                                return $resolver->attachRenderedTargets($edges->take(100), $tenant); // both directions combined
                            })
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),

                Section::make('Metadata (Safe Subset)')
                    ->schema([
                        ViewEntry::make('meta_jsonb')
                            ->label('')
                            ->view('filament.infolists.entries.snapshot-json')
                            ->state(fn (InventoryItem $record) => $record->meta_jsonb ?? [])
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
            ]);
    }

    public static function table(Table $table): Table
    {
        $typeOptions = collect(static::allTypeMeta())
            ->mapWithKeys(fn (array $row) => [($row['type'] ?? null) => ($row['label'] ?? $row['type'] ?? null)])
            ->filter(fn ($label, $type) => is_string($type) && $type !== '' && is_string($label) && $label !== '')
            ->all();

        $categoryOptions = collect(static::allTypeMeta())
            ->mapWithKeys(fn (array $row) => [($row['category'] ?? null) => ($row['category'] ?? null)])
            ->filter(fn ($value, $key) => is_string($key) && $key !== '')
            ->all();

        return $table
            ->defaultSort('last_seen_at', 'desc')
            ->columns([
                Tables\Columns\TextColumn::make('display_name')
                    ->label('Name')
                    ->searchable(),
                Tables\Columns\TextColumn::make('policy_type')
                    ->label('Type')
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyType))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyType)),
                Tables\Columns\TextColumn::make('category')
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::PolicyCategory))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::PolicyCategory)),
                Tables\Columns\TextColumn::make('platform')
                    ->badge()
                    ->formatStateUsing(TagBadgeRenderer::label(TagBadgeDomain::Platform))
                    ->color(TagBadgeRenderer::color(TagBadgeDomain::Platform)),
                Tables\Columns\TextColumn::make('last_seen_at')
                    ->label('Last seen')
                    ->since(),
                Tables\Columns\TextColumn::make('lastSeenRun.status')
                    ->label('Run')
                    ->badge()
                    ->formatStateUsing(function (?string $state): string {
                        if (! filled($state)) {
                            return '—';
                        }

                        return BadgeRenderer::spec(BadgeDomain::InventorySyncRunStatus, $state)->label;
                    })
                    ->color(function (?string $state): string {
                        if (! filled($state)) {
                            return 'gray';
                        }

                        return BadgeRenderer::spec(BadgeDomain::InventorySyncRunStatus, $state)->color;
                    })
                    ->icon(function (?string $state): ?string {
                        if (! filled($state)) {
                            return null;
                        }

                        return BadgeRenderer::spec(BadgeDomain::InventorySyncRunStatus, $state)->icon;
                    })
                    ->iconColor(function (?string $state): ?string {
                        if (! filled($state)) {
                            return 'gray';
                        }

                        $spec = BadgeRenderer::spec(BadgeDomain::InventorySyncRunStatus, $state);

                        return $spec->iconColor ?? $spec->color;
                    }),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('policy_type')
                    ->options($typeOptions)
                    ->searchable(),
                Tables\Filters\SelectFilter::make('category')
                    ->options($categoryOptions)
                    ->searchable(),
            ])
            ->actions([
                Actions\ViewAction::make(),
            ])
            ->bulkActions([]);
    }

    public static function getEloquentQuery(): Builder
    {
        $tenantId = Tenant::current()->getKey();

        return parent::getEloquentQuery()
            ->when($tenantId, fn (Builder $query) => $query->where('tenant_id', $tenantId))
            ->with('lastSeenRun');
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListInventoryItems::route('/'),
            'view' => Pages\ViewInventoryItem::route('/{record}'),
        ];
    }

    /**
     * @return array{label:?string,category:?string,restore:?string,risk:?string}|array<string,mixed>
     */
    private static function typeMeta(?string $type): array
    {
        if ($type === null) {
            return [];
        }

        return InventoryPolicyTypeMeta::metaFor($type);
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    private static function allTypeMeta(): array
    {
        return InventoryPolicyTypeMeta::all();
    }
}
