<?php

declare(strict_types=1);

namespace App\Filament\Resources\Concerns;

use App\Business\MasterData\DberpDocumentAddressSnapshotService;
use App\Models\DberpCustomer;
use App\Models\DberpSupplier;
use App\Models\DberpWarehouse;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Section;
use Illuminate\Database\Eloquent\Model;

trait HasDberpDocumentAddressSnapshots
{
    protected static function getDberpCounterpartySnapshotSection(
        string $title,
        string $prefix,
        ?callable $allowMasterFallbackResolver = null,
    ): Section {
        $allowMasterFallbackResolver ??= static fn (?Model $record): bool => static::resolveCounterpartySnapshotAllowMasterFallback($record);

        return Section::make($title)
            ->description(__('dberp.hints.document_address_snapshot'))
            ->schema([
                Placeholder::make("_{$prefix}_address_overview")
                    ->label(__('dberp.sections.region_address'))
                    ->content(fn (?Model $record): string => static::formatCounterpartySnapshotAddressOverview(
                        $record,
                        $prefix,
                        $allowMasterFallbackResolver,
                    ))
                    ->columnSpanFull(),
                TextInput::make("{$prefix}_contact_person_snapshot")
                    ->label(__('dberp.fields.contact_person'))
                    ->disabled()
                    ->dehydrated(false)
                    ->formatStateUsing(function ($state, ?Model $record) use ($prefix, $allowMasterFallbackResolver): string {
                        $party = static::resolveCounterpartyMasterRecord($record, $prefix);
                        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

                        return $snapshotService->resolveSnapshotFieldDisplay(
                            filled($state) ? (string) $state : null,
                            $party?->contact_person,
                            $allowMasterFallbackResolver($record),
                        );
                    }),
                TextInput::make("{$prefix}_mobile_snapshot")
                    ->label(__('dberp.fields.mobile'))
                    ->disabled()
                    ->dehydrated(false)
                    ->formatStateUsing(function ($state, ?Model $record) use ($prefix, $allowMasterFallbackResolver): string {
                        $party = static::resolveCounterpartyMasterRecord($record, $prefix);
                        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

                        return $snapshotService->resolveSnapshotFieldDisplay(
                            filled($state) ? (string) $state : null,
                            $party?->mobile,
                            $allowMasterFallbackResolver($record),
                        );
                    }),
                TextInput::make("{$prefix}_phone_snapshot")
                    ->label(__('dberp.fields.phone'))
                    ->disabled()
                    ->dehydrated(false)
                    ->formatStateUsing(function ($state, ?Model $record) use ($prefix, $allowMasterFallbackResolver): string {
                        $party = static::resolveCounterpartyMasterRecord($record, $prefix);
                        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

                        return $snapshotService->resolveSnapshotFieldDisplay(
                            filled($state) ? (string) $state : null,
                            $party?->phone,
                            $allowMasterFallbackResolver($record),
                        );
                    }),
            ])
            ->columns(2)
            ->visible(fn (?Model $record): bool => $record !== null);
    }

    protected static function getDberpWarehouseSnapshotSection(
        string $title,
        string $prefix,
        ?callable $allowMasterFallbackResolver = null,
    ): Section {
        $allowMasterFallbackResolver ??= static fn (?Model $record): bool => static::resolveCounterpartySnapshotAllowMasterFallback($record);

        return Section::make($title)
            ->description(__('dberp.hints.document_address_snapshot'))
            ->schema([
                Placeholder::make("_{$prefix}_address_overview")
                    ->label(__('dberp.sections.region_address'))
                    ->content(fn (?Model $record): string => static::formatWarehouseSnapshotAddressOverview(
                        $record,
                        $prefix,
                        $allowMasterFallbackResolver,
                    ))
                    ->columnSpanFull(),
                TextInput::make("{$prefix}_contact_phone_snapshot")
                    ->label(__('dberp.fields.contact_phone'))
                    ->disabled()
                    ->dehydrated(false)
                    ->formatStateUsing(function ($state, ?Model $record) use ($prefix, $allowMasterFallbackResolver): string {
                        $warehouse = static::resolveWarehouseMasterRecord($record, $prefix);
                        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

                        return $snapshotService->resolveSnapshotFieldDisplay(
                            filled($state) ? (string) $state : null,
                            $warehouse?->contact_phone,
                            $allowMasterFallbackResolver($record),
                        );
                    }),
            ])
            ->columns(2)
            ->visible(fn (?Model $record): bool => $record !== null);
    }

    /**
     * @param  callable(?Model): bool  $allowMasterFallbackResolver
     */
    protected static function formatCounterpartySnapshotAddressOverview(
        ?Model $record,
        string $prefix,
        callable $allowMasterFallbackResolver,
    ): string {
        if ($record === null) {
            return app(DberpDocumentAddressSnapshotService::class)->emptySnapshotDisplayLabel();
        }

        $party = static::resolveCounterpartyMasterRecord($record, $prefix);
        $allowFallback = $allowMasterFallbackResolver($record);
        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

        $countrySnapshot = $record->getAttribute("{$prefix}_country_code_snapshot");
        $regionSnapshot = $record->getAttribute("{$prefix}_region_name_snapshot");
        $addressSnapshot = $record->getAttribute("{$prefix}_address_snapshot");

        return $snapshotService->formatAddressSummary(
            filled($countrySnapshot) ? (string) $countrySnapshot : null,
            filled($regionSnapshot) ? (string) $regionSnapshot : null,
            filled($addressSnapshot) ? (string) $addressSnapshot : null,
            $allowFallback ? $party?->country_code : null,
            $allowFallback ? $party?->region_name_snapshot : null,
            $allowFallback ? $party?->address : null,
            $allowFallback,
        );
    }

    /**
     * @param  callable(?Model): bool  $allowMasterFallbackResolver
     */
    protected static function formatWarehouseSnapshotAddressOverview(
        ?Model $record,
        string $prefix,
        callable $allowMasterFallbackResolver,
    ): string {
        if ($record === null) {
            return app(DberpDocumentAddressSnapshotService::class)->emptySnapshotDisplayLabel();
        }

        $warehouse = static::resolveWarehouseMasterRecord($record, $prefix);
        $allowFallback = $allowMasterFallbackResolver($record);
        $snapshotService = app(DberpDocumentAddressSnapshotService::class);

        $countrySnapshot = $record->getAttribute("{$prefix}_country_code_snapshot");
        $regionSnapshot = $record->getAttribute("{$prefix}_region_name_snapshot");
        $addressSnapshot = $record->getAttribute("{$prefix}_address_snapshot");

        return $snapshotService->formatAddressSummary(
            filled($countrySnapshot) ? (string) $countrySnapshot : null,
            filled($regionSnapshot) ? (string) $regionSnapshot : null,
            filled($addressSnapshot) ? (string) $addressSnapshot : null,
            $allowFallback ? $warehouse?->country_code : null,
            $allowFallback ? $warehouse?->region_name_snapshot : null,
            $allowFallback ? $warehouse?->address : null,
            $allowFallback,
        );
    }

    protected static function resolveCounterpartySnapshotAllowMasterFallback(?Model $record): bool
    {
        if ($record === null) {
            return true;
        }

        $status = $record->getAttribute('status');

        return app(DberpDocumentAddressSnapshotService::class)->allowCounterpartyMasterDataFallback(
            is_string($status) ? $status : null,
        );
    }

    protected static function resolveCounterpartyMasterRecord(?Model $record, string $prefix): DberpCustomer|DberpSupplier|null
    {
        if ($record === null) {
            return null;
        }

        if ($prefix === 'customer') {
            if ($record->relationLoaded('customer')) {
                $related = $record->getRelation('customer');

                return $related instanceof DberpCustomer ? $related : null;
            }

            $customerId = $record->getAttribute('customer_id');

            return $customerId ? DberpCustomer::query()->find($customerId) : null;
        }

        if ($prefix === 'supplier') {
            if ($record->relationLoaded('supplier')) {
                $related = $record->getRelation('supplier');

                return $related instanceof DberpSupplier ? $related : null;
            }

            $supplierId = $record->getAttribute('supplier_id');

            return $supplierId ? DberpSupplier::query()->find($supplierId) : null;
        }

        return null;
    }

    protected static function resolveWarehouseMasterRecord(?Model $record, string $prefix): ?DberpWarehouse
    {
        if ($record === null) {
            return null;
        }

        $foreignKey = match ($prefix) {
            'warehouse' => 'warehouse_id',
            'from_warehouse' => 'from_warehouse_id',
            'to_warehouse' => 'to_warehouse_id',
            default => "{$prefix}_id",
        };

        $relation = match ($prefix) {
            'warehouse' => 'warehouse',
            'from_warehouse' => 'fromWarehouse',
            'to_warehouse' => 'toWarehouse',
            default => null,
        };

        if ($relation !== null && $record->relationLoaded($relation)) {
            $related = $record->getRelation($relation);

            return $related instanceof DberpWarehouse ? $related : null;
        }

        $warehouseId = $record->getAttribute($foreignKey);

        return $warehouseId ? DberpWarehouse::query()->find($warehouseId) : null;
    }
}
