<?php

namespace App\Filament\Central\Resources\TenantResource\RelationManagers;

use App\Models\Branch;
use App\Models\Central\Tenant;
use App\Models\Sales\Till;
use App\Services\AuditLog;
use App\Services\CurrentContext;
use App\Services\DocumentNumberService;
use App\Support\Invoice\InvoiceDocument;
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Notifications\Notification;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;
use Filament\Support\Enums\Operation;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;

/**
 * Branch management for a tenant, from the landlord panel
 * (docs/migration-plan.md Phase 10, resolving the deferral in Decisions Log
 * #5 and #15).
 *
 * This is a REBUILD, not a port: `Central\BranchManagementController` is dead
 * code in the source — it imports a non-existent `App\Models\Tenant` and calls
 * `$tenant->run()`, so every branch create/edit/delete fatals. The validation
 * rules it declares are unambiguous and are honoured exactly (name required +
 * unique, optional phone/email/city/country, and the "can't delete a branch
 * with tills assigned" guard); only the broken tenant-context mechanism is
 * replaced — with the relationship itself, which constrains
 * `warehouses.tenant_id` to this tenant on both read and write.
 *
 * Address is required (unlike the source): invoice prints put the branch
 * address on the letterhead ({@see InvoiceDocument}),
 * so a branch without one prints a blank line where the customer expects to
 * see where the sale was made.
 */
class BranchesRelationManager extends RelationManager
{
    protected static string $relationship = 'branches';

    protected static ?string $title = 'Branches';

    protected static ?string $recordTitleAttribute = 'name';

    /**
     * No per-model policy check. Authorization on the landlord panel is
     * "you are an authenticated central admin, full stop" — the source's
     * central routes carry only `middleware('central')`, with no permission
     * gate of any kind (the tenant RBAC ceiling does not apply to the
     * landlord). Without this, Filament would look for a BranchPolicy that
     * deliberately does not exist and deny everything.
     */
    protected static bool $shouldSkipAuthorization = true;

    public function form(Schema $schema): Schema
    {
        return $schema->components([
            TextInput::make('name')
                ->required()
                ->maxLength(150)
                // Unique within this tenant's branches — the source's
                // `unique:warehouses,name` was written for a single-tenant
                // schema; scoping it to the tenant is what that rule means now
                // that `warehouses` holds every tenant's rows.
                ->rule(fn (?Branch $record) => Rule::unique('warehouses', 'name')
                    ->where('tenant_id', $this->getOwnerRecord()->getKey())
                    ->ignore($record?->id)),
            TextInput::make('phone')->maxLength(30),
            TextInput::make('email')->email()->maxLength(150),
            TextInput::make('address')->required()->maxLength(300),
            TextInput::make('city')->maxLength(100),
            TextInput::make('country')->maxLength(100),
            Toggle::make('is_active')->default(true),
            // Create-time convenience: every branch starts life with a till at
            // the counter. Deliberately create-only — the main till is created
            // once with the branch; renaming/moving it later is a till edit.
            Toggle::make('create_main_till')
                ->label('Automatically create the Main Till')
                ->helperText('Creates a till named "<branch name> Main Till" for this branch.')
                ->default(true)
                ->hiddenOn(Operation::Edit),
        ])->columns(2);
    }

    public function table(Table $table): Table
    {
        return $table
            ->columns([
                TextColumn::make('name')->searchable()->sortable(),
                TextColumn::make('phone')->placeholder('—'),
                TextColumn::make('email')->placeholder('—'),
                TextColumn::make('city')->placeholder('—'),
                TextColumn::make('tills_count')->label('Tills')->counts('tills'),
                IconColumn::make('is_active')->boolean(),
            ])
            ->defaultSort('name')
            ->headerActions([
                CreateAction::make()
                    // Capture the create-only toggle before it is dropped from
                    // the branch's own data (it is not a warehouses column).
                    ->mutateFormDataUsing(function (array $data) use (&$shouldCreateMainTill): array {
                        $shouldCreateMainTill = (bool) ($data['create_main_till'] ?? true);
                        unset($data['create_main_till']);

                        return $data;
                    })
                    ->after(function (Branch $record) use (&$shouldCreateMainTill): void {
                        static::auditBranch($record, 'branch.created');

                        if ($shouldCreateMainTill) {
                            static::createMainTill($record);
                        }
                    }),
            ])
            ->recordActions([
                EditAction::make()
                    ->after(fn (Branch $record) => static::auditBranch($record, 'branch.updated')),
                DeleteAction::make()
                    // Ported guard: a branch with tills assigned cannot be
                    // deleted (the tills would be orphaned mid-shift).
                    ->action(function (Branch $record, DeleteAction $action): void {
                        if ($record->tills()->exists()) {
                            Notification::make()
                                ->title('Cannot delete: branch has tills assigned.')
                                ->danger()
                                ->send();

                            $action->cancel();

                            return;
                        }

                        $record->delete();
                        static::auditBranch($record, 'branch.deleted');

                        Notification::make()->title('Branch deleted.')->success()->send();
                    }),
            ]);
    }

    /**
     * Landlord operations are written to the affected tenant's audit trail
     * with the central operator's identity in the context (they are not a
     * tenant user, so actor_id stays null) — mirroring TenantResource::audit().
     */
    protected static function auditBranch(Branch $branch, string $action): void
    {
        $tenant = $branch->tenant_id ? Tenant::query()->find($branch->tenant_id) : null;

        if ($tenant === null) {
            return;
        }

        $context = [
            'name' => $branch->name,
            'phone' => $branch->phone,
            'city' => $branch->city,
            'central_admin' => Auth::guard('central')->user()?->email,
        ];

        app(CurrentContext::class)->runForTenant($tenant, fn () => AuditLog::record($action, $branch, $context));
    }

    /**
     * Provision the branch's main till. Central has no tenant bound, so the
     * identifier and tenant stamping happen inside the tenant's own context —
     * the same idiom TillsRelationManager uses for every landlord till create.
     */
    protected static function createMainTill(Branch $branch): void
    {
        $tenant = $branch->tenant_id ? Tenant::query()->find($branch->tenant_id) : null;

        if ($tenant === null) {
            return;
        }

        app(CurrentContext::class)->runForTenant($tenant, function () use ($branch): void {
            $till = Till::create([
                'identifier' => app(DocumentNumberService::class)->next('till'),
                'name' => $branch->name.' Main Till',
                'branch_id' => $branch->id,
                'is_active' => true,
            ]);

            AuditLog::record('till.created', $till, [
                'name' => $till->name,
                'identifier' => $till->identifier,
                'branch' => $branch->name,
                'central_admin' => Auth::guard('central')->user()?->email,
            ]);
        });
    }
}
