<?php

declare(strict_types=1);

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

namespace App\Tools\Context;

use App\Tools\Entity\EntityReference;

/**
 * 传输无关的当前页上下文。只承载已批准字段，不含 Filament/Livewire/Request 对象或未保存表单。
 * 上下文仅作指代提示，不是授权令牌，也不能替代 Tool 入参校验。
 */
final readonly class ErpPageContext
{
    public const QUERY_KIND = 'ctx_kind';

    public const QUERY_TYPE = 'ctx_type';

    public const QUERY_ID = 'ctx_id';

    public const QUERY_SOURCE = 'ctx_source';

    /**
     * @var list<string>
     */
    private const ALLOWED_KEYS = ['page_kind', 'entity_ref', 'source'];

    /**
     * @var list<string>
     */
    private const FORBIDDEN_KEYS = [
        'url',
        'href',
        'route',
        'route_name',
        'path',
        'model',
        'class',
        'request',
        'livewire',
        'form',
        'filters',
        'selected',
        'unsaved',
    ];

    public function __construct(
        public PageKind $pageKind,
        public EntityReference $entityRef,
        public PageContextSource $source,
    ) {}

    /**
     * @return array{page_kind: string, entity_ref: array{entity_type: string, entity_id: int, label: string}, source: string}
     */
    public function toArray(): array
    {
        return [
            'page_kind' => $this->pageKind->value,
            'entity_ref' => $this->entityRef->toArray(),
            'source' => $this->source->value,
        ];
    }

    /**
     * @return array{ctx_kind: string, ctx_type: string, ctx_id: int, ctx_source: string}
     */
    public function toQueryParameters(): array
    {
        return [
            self::QUERY_KIND => $this->pageKind->value,
            self::QUERY_TYPE => $this->entityRef->entityType->value,
            self::QUERY_ID => $this->entityRef->entityId,
            self::QUERY_SOURCE => $this->source->value,
        ];
    }

    public static function tryFromArray(mixed $value): ?self
    {
        if (! is_array($value)) {
            return null;
        }

        foreach (array_keys($value) as $key) {
            if (! is_string($key) || in_array($key, self::FORBIDDEN_KEYS, true) || ! in_array($key, self::ALLOWED_KEYS, true)) {
                return null;
            }
        }

        $pageKind = PageKind::tryFromMixed($value['page_kind'] ?? null);
        $source = PageContextSource::tryFromMixed($value['source'] ?? null);
        $entityRef = EntityReference::tryFromArray($value['entity_ref'] ?? null);

        if (! $pageKind instanceof PageKind || ! $source instanceof PageContextSource || ! $entityRef instanceof EntityReference) {
            return null;
        }

        if ($pageKind->entityType() !== $entityRef->entityType) {
            return null;
        }

        return new self($pageKind, $entityRef, $source);
    }
}
