<?php

namespace App\Livewire;

use App\Filament\Resources\EntraGroupResource;
use App\Models\EntraGroup;
use App\Models\ManagedEnvironment;
use App\Support\OperationRunLinks;
use Filament\Actions\Action;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Filament\Tables\TableComponent;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;

class EntraGroupCachePickerTable extends TableComponent
{
    public string $sourceGroupId;

    public function mount(string $sourceGroupId): void
    {
        $this->sourceGroupId = $sourceGroupId;
    }

    public function table(Table $table): Table
    {
        $tenantId = ManagedEnvironment::current()?->getKey();

        $query = EntraGroup::query();

        if ($tenantId) {
            $query->where('managed_environment_id', $tenantId);
        } else {
            $query->whereRaw('1 = 0');
        }

        $stalenessDays = (int) config('directory_groups.staleness_days', 30);
        $cutoff = now('UTC')->subDays(max(1, $stalenessDays));

        return $table
            ->queryStringIdentifier('entraGroupCachePicker')
            ->query($query)
            ->defaultSort('display_name')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::picker())
            ->defaultPaginationPageOption(25)
            ->searchable()
            ->searchPlaceholder('Search groups…')
            ->deferLoading(! app()->runningUnitTests())
            ->columns([
                TextColumn::make('display_name')
                    ->label('Name')
                    ->searchable()
                    ->sortable()
                    ->wrap()
                    ->limit(60),
                TextColumn::make('type')
                    ->label('Type')
                    ->badge()
                    ->state(fn (EntraGroup $record): string => $this->groupTypeLabel($this->groupType($record)))
                    ->color(fn (EntraGroup $record): string => $this->groupTypeColor($this->groupType($record)))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('entra_id')
                    ->label('ID')
                    ->formatStateUsing(fn (?string $state): string => filled($state) ? ('…'.substr($state, -8)) : '—')
                    ->extraAttributes(['class' => 'font-mono'])
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('last_seen_at')
                    ->label('Last seen')
                    ->since()
                    ->sortable(),
            ])
            ->filters([
                SelectFilter::make('stale')
                    ->label('Stale')
                    ->options([
                        '1' => 'Stale',
                        '0' => 'Fresh',
                    ])
                    ->query(function (Builder $query, array $data) use ($cutoff): Builder {
                        $value = $data['value'] ?? null;

                        if ($value === null || $value === '') {
                            return $query;
                        }

                        if ((string) $value === '1') {
                            return $query->where(function (Builder $q) use ($cutoff): void {
                                $q->whereNull('last_seen_at')
                                    ->orWhere('last_seen_at', '<', $cutoff);
                            });
                        }

                        return $query->where('last_seen_at', '>=', $cutoff);
                    }),

                SelectFilter::make('group_type')
                    ->label('Type')
                    ->options([
                        'security' => 'Security',
                        'microsoft365' => 'Microsoft 365',
                        'mail' => 'Mail-enabled',
                        'unknown' => 'Unknown',
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        $value = (string) ($data['value'] ?? '');

                        if ($value === '') {
                            return $query;
                        }

                        return match ($value) {
                            'microsoft365' => $query->whereJsonContains('group_types', 'Unified'),
                            'security' => $query
                                ->where('security_enabled', true)
                                ->where(function (Builder $q): void {
                                    $q->whereNull('group_types')
                                        ->orWhereJsonDoesntContain('group_types', 'Unified');
                                }),
                            'mail' => $query
                                ->where('mail_enabled', true)
                                ->where(function (Builder $q): void {
                                    $q->whereNull('group_types')
                                        ->orWhereJsonDoesntContain('group_types', 'Unified');
                                }),
                            'unknown' => $query
                                ->where(function (Builder $q): void {
                                    $q->whereNull('group_types')
                                        ->orWhereJsonDoesntContain('group_types', 'Unified');
                                })
                                ->where('security_enabled', false)
                                ->where('mail_enabled', false),
                            default => $query,
                        };
                    }),
            ])
            ->actions([
                Action::make('select')
                    ->label('Select')
                    ->icon('heroicon-o-check')
                    ->color('primary')
                    ->action(function (EntraGroup $record): void {
                        $this->dispatch('entra-group-cache-picked', sourceGroupId: $this->sourceGroupId, entraId: (string) $record->entra_id);
                    }),
            ])
            ->emptyStateHeading('No cached groups found')
            ->emptyStateDescription('Run “Sync Groups” first, then come back here.')
            ->emptyStateActions([
                Action::make('open_groups')
                    ->label('Directory Groups')
                    ->icon('heroicon-o-user-group')
                    ->url(fn (): string => EntraGroupResource::getUrl('index', tenant: ManagedEnvironment::current())),
                Action::make('open_sync_runs')
                    ->label('Operations')
                    ->icon('heroicon-o-clock')
                    ->url(fn (): string => OperationRunLinks::index(ManagedEnvironment::current())),
            ]);
    }

    public function render(): View
    {
        return view('livewire.entra-group-cache-picker-table');
    }

    private function groupType(EntraGroup $record): string
    {
        $groupTypes = $record->group_types;

        if (is_array($groupTypes) && in_array('Unified', $groupTypes, true)) {
            return 'microsoft365';
        }

        if ($record->security_enabled) {
            return 'security';
        }

        if ($record->mail_enabled) {
            return 'mail';
        }

        return 'unknown';
    }

    private function groupTypeLabel(string $type): string
    {
        return match ($type) {
            'microsoft365' => 'Microsoft 365',
            'security' => 'Security',
            'mail' => 'Mail-enabled',
            default => 'Unknown',
        };
    }

    private function groupTypeColor(string $type): string
    {
        return match ($type) {
            'microsoft365' => 'info',
            'security' => 'success',
            'mail' => 'warning',
            default => 'gray',
        };
    }
}
