<?php

namespace App\Filament\Resources\Clients\RelationManagers;

use Filament\Schemas\Schema;
use Closure;
use Filament\Tables\Columns\TextColumn;
use Filament\Actions\CreateAction;
use App\Models\Account;
use Filament\Actions\EditAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use App\Actions\Balances\CreateBalanceAction;
use App\Actions\Ledgers\CreateLedgerAction;
use App\DataObjects\CreateLedgerDTO;
use App\Models\Branch;
use App\Models\Journal;
use Awcodes\TableRepeater\Components\TableRepeater;
use Awcodes\TableRepeater\Header;
use Filament\Forms;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Textarea;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Pipeline;

class JournalsRelationManager extends RelationManager
{
    protected static string $relationship = 'journals';

    protected static ?string $title = 'Journal Entries (Adjustments)';

    public function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                Select::make('branch_id')
                    ->label('Branch')
                    ->options(fn () => Branch::where('client_id', $this->getOwnerRecord()->id)->pluck('code', 'id'))
                    ->required()
                    ->default(fn () => Branch::where('client_id', $this->getOwnerRecord()->id)->first()?->id),
                
                DatePicker::make('happened_on')
                    ->label('Date')
                    ->required()
                    ->default(now()),

                TextInput::make('series')
                    ->label('Reference/Series #')
                    ->required(),

                Textarea::make('description')
                    ->label('Description')
                    ->columnSpanFull(),

                TableRepeater::make('ledgers')
                    ->relationship('ledgers')
                    ->headers([
                        Header::make('Account'),
                        Header::make('Description'),
                        Header::make('Debit'),
                        Header::make('Credit'),
                    ])
                    ->schema([
                        Select::make('account_id')
                            ->relationship('account', 'account', fn (Builder $query) => $query->where('client_id', $this->getOwnerRecord()->id))
                            ->searchable()
                            ->preload()
                            ->required(),
                        TextInput::make('description'),
                        TextInput::make('debit_amount')
                            ->numeric()
                            ->default(0),
                        TextInput::make('credit_amount')
                            ->numeric()
                            ->default(0),
                    ])
                    ->columnSpanFull()
                    ->minItems(2)
                    ->live()
                    ->rules([
                        fn (): Closure => function (string $attribute, $value, Closure $fail) {
                            $debit = collect($value)->sum('debit_amount');
                            $credit = collect($value)->sum('credit_amount');
                            if (abs($debit - $credit) > 0.01) {
                                $fail("Total Debit (" . number_format($debit, 2) . ") must equal Total Credit (" . number_format($credit, 2) . ").");
                            }
                        },
                    ])
                    ->afterStateUpdated(function ($state, $component) {
                        // Optional: Validation logic
                    }),
            ]);
    }

    public function table(Table $table): Table
    {
        return $table
            ->recordTitleAttribute('description')
            ->columns([
                TextColumn::make('happened_on')
                    ->date()
                    ->sortable(),
                TextColumn::make('series')
                    ->searchable(),
                TextColumn::make('description')
                    ->limit(50),
                TextColumn::make('total_debit')
                    ->label('Total Debit')
                    ->state(fn (Journal $record) => $record->ledgers->sum('debit_amount'))
                    ->money('PHP'),
                TextColumn::make('total_credit')
                    ->label('Total Credit')
                    ->state(fn (Journal $record) => $record->ledgers->sum('credit_amount'))
                    ->money('PHP'),
            ])
            ->filters([
                //
            ])
            ->headerActions([
                CreateAction::make()
                    ->label('Add Adjustment Entry')
                    ->using(function (array $data, string $model) {
                        return DB::transaction(function () use ($data, $model) {
                            $ledgersData = $data['ledgers'] ?? [];
                            $journalData = Arr::except($data, ['ledgers']);
                            $journalData['client_id'] = $this->getOwnerRecord()->id;

                            $journal = $model::create($journalData);

                            foreach ($ledgersData as $ledger) {
                                $ledgerPayload = new CreateLedgerDTO(
                                    branch_id: $journal->branch_id,
                                    amount: ($ledger['debit_amount'] > 0) ? $ledger['debit_amount'] : $ledger['credit_amount'],
                                    ledger: null, // Will be created
                                    transaction: null, // No transaction
                                    journal: $journal,
                                    account: Account::find($ledger['account_id']),
                                    type: ($ledger['debit_amount'] > 0) ? 'debit' : 'credit'
                                );
                                
                                Pipeline::send(passable: $ledgerPayload)->through(
                                    [
                                        CreateLedgerAction::class,
                                    ]
                                )->thenReturn();
                            }
                            return $journal;
                        });
                    }),
            ])
            ->recordActions([
                EditAction::make(),
                DeleteAction::make(),
            ])
            ->toolbarActions([
                BulkActionGroup::make([
                    DeleteBulkAction::make(),
                ]),
            ]);
    }
}
