<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Filament\Pages;

use App\Business\Report\SalesAnalysisReportService;
use App\Business\Sales\Enums\SalesOrderStatus;
use App\Filament\Concerns\InteractsWithDberpPermissions;
use App\Filament\Pages\Concerns\CachesDberpReportAnalysisResults;
use App\Filament\Pages\Concerns\HasDberpAnalysisPageCsvExport;
use App\Filament\Pages\Concerns\InteractsWithDberpReportPage;
use App\Models\DberpEmployee;
use App\Models\DberpProductSku;
use App\Services\DberpPermissionService;
use App\Support\DberpFilamentMasterDataSelectOptions;
use App\Support\DberpProductSkuSelectOptions;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Pages\Page;
use Filament\Schemas\Components\Actions;
use Filament\Schemas\Components\Form;
use Filament\Schemas\Schema;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use UnitEnum;

/**
 * @property-read Schema $form
 */
final class DberpSalesAnalysisPage extends Page
{
    use CachesDberpReportAnalysisResults;
    use HasDberpAnalysisPageCsvExport;
    use InteractsWithDberpPermissions;
    use InteractsWithDberpReportPage;

    private const REPORT_KEY = 'sales-analysis';

    protected static ?string $slug = 'sales-analysis';

    protected static ?int $navigationSort = 50;

    protected string $view = 'filament.pages.dberp-sales-analysis-page';

    /**
     * @var array<string, mixed>|null
     */
    public ?array $data = [];

    /**
     * @var array<string, int|string|float>
     */
    public array $summary = [];

    /**
     * @var list<array{date: string, order_count: int, amount: string}>
     */
    public array $trend = [];

    /**
     * @var list<array{id: int, name: string, amount: string, order_count: int}>
     */
    public array $topCustomers = [];

    /**
     * @var list<array{id: int, name: string, amount: string, quantity: string, order_count: int}>
     */
    public array $topProducts = [];

    public function mount(): void
    {
        $this->form->fill([
            'business_time_from' => now()->startOfMonth()->toDateString(),
            'business_time_until' => now()->toDateString(),
            'customer_id' => null,
            'handler_employee_id' => null,
            'category_id' => null,
            'product_id' => null,
            'product_sku_id' => null,
            'sales_ranking_dimension' => 'product',
            'status' => null,
        ]);

        $this->refreshData();
    }

    public static function getNavigationGroup(): string|UnitEnum|null
    {
        return __('dberp.nav.report_analysis');
    }

    public static function getNavigationLabel(): string
    {
        return __('dberp.resources.sales_analysis.label');
    }

    public static function getNavigationIcon(): string|BackedEnum|Htmlable|null
    {
        return null;
    }

    public static function canAccess(): bool
    {
        return Auth::check() && self::allowsPermission(DberpPermissionService::NAV_SALES_ANALYSIS);
    }

    public function getTitle(): string|Htmlable
    {
        return __('dberp.resources.sales_analysis.label');
    }

    public function form(Schema $schema): Schema
    {
        return $schema
            ->components([
                Form::make([
                    DatePicker::make('business_time_from')
                        ->label(__('dberp.fields.business_time_from'))
                        ->default(now()->startOfMonth()->toDateString()),
                    DatePicker::make('business_time_until')
                        ->label(__('dberp.fields.business_time_until'))
                        ->default(now()->toDateString()),
                    DberpFilamentMasterDataSelectOptions::applyDeferredSearch(
                        Select::make('customer_id')
                            ->label(__('dberp.fields.customer'))
                            ->nullable(),
                        fn (): array => DberpFilamentMasterDataSelectOptions::customers(enabledOnly: true),
                    ),
                    DberpFilamentMasterDataSelectOptions::applyDeferredSearch(
                        Select::make('handler_employee_id')
                            ->label(__('dberp.fields.handler_employee'))
                            ->nullable(),
                        fn (): array => DberpEmployee::selectOptionsForFilament(fn (Builder $q) => $q->where('is_enabled', true)),
                    ),
                    DberpFilamentMasterDataSelectOptions::applyDeferredSearch(
                        Select::make('category_id')
                            ->label(__('dberp.fields.category'))
                            ->nullable(),
                        fn (): array => DberpFilamentMasterDataSelectOptions::productCategories(),
                    ),
                    DberpFilamentMasterDataSelectOptions::applyDeferredSearch(
                        Select::make('product_id')
                            ->label(__('dberp.fields.product'))
                            ->live()
                            ->nullable(),
                        fn (): array => DberpFilamentMasterDataSelectOptions::products(enabledOnly: true),
                    ),
                    DberpFilamentMasterDataSelectOptions::applyDeferredSearch(
                        Select::make('product_sku_id')
                            ->label(__('dberp.fields.product_spec'))
                            ->nullable(),
                        fn (): array => $this->productSkuOptionsForAnalysisFilter(
                            (int) ($this->data['product_id'] ?? 0),
                        ),
                    ),
                    Select::make('sales_ranking_dimension')
                        ->label(__('dberp.fields.sales_analysis_ranking_dimension'))
                        ->options(__('dberp.options.report_ranking_dimension'))
                        ->default('product'),
                    Select::make('status')
                        ->label(__('dberp.fields.status'))
                        ->options(SalesOrderStatus::statisticsScopeOptions())
                        ->nullable(),
                ])
                    ->columns(3)
                    ->livewireSubmitHandler('refreshData')
                    ->footer([
                        Actions::make([
                            Action::make('refreshData')
                                ->label(__('dberp.actions.refresh_analysis'))
                                ->submit('refreshData'),
                        ]),
                    ]),
            ])
            ->statePath('data');
    }

    public function refreshData(): void
    {
        $service = app(SalesAnalysisReportService::class);
        $filters = $service->normalizeFilters($this->form->getState());

        /** @var array{
         *     summary: array<string, int|string|float>,
         *     trend: list<array<string, string>>,
         *     topCustomers: list<array<string, mixed>>,
         *     topProducts: list<array<string, mixed>>
         * } $payload */
        $payload = $this->rememberReportAnalysis(self::REPORT_KEY, $filters, fn (): array => [
            'summary' => $service->summary($filters),
            'trend' => $service->dailyTrend($filters),
            'topCustomers' => $service->topCustomers($filters, 8),
            'topProducts' => $service->topProducts($filters, 8),
        ]);

        $this->summary = $payload['summary'];
        $this->trend = $payload['trend'];
        $this->topCustomers = $payload['topCustomers'];
        $this->topProducts = $payload['topProducts'];
    }

    protected function reportExportKey(): string
    {
        return self::REPORT_KEY;
    }

    /**
     * @return array<int|string, string>
     */
    private function productSkuOptionsForAnalysisFilter(int $productId): array
    {
        if ($productId <= 0) {
            return [];
        }

        return DberpProductSku::query()
            ->where('product_id', $productId)
            ->with(['product.unit'])
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get()
            ->mapWithKeys(fn (DberpProductSku $sku): array => [$sku->getKey() => DberpProductSkuSelectOptions::labelForSku($sku)])
            ->all();
    }
}
