<?php

declare(strict_types=1);

namespace App\Support\Navigation;

final readonly class RelatedContextEntry
{
    /**
     * @param  array<string, mixed>|null  $reference
     */
    public function __construct(
        public string $key,
        public string $label,
        public string $value,
        public ?string $secondaryValue,
        public ?string $targetUrl,
        public string $targetKind,
        public string $availability,
        public ?string $unavailableReason,
        public ?string $contextBadge,
        public int $priority,
        public string $actionLabel,
        public ?array $reference = null,
    ) {}

    public static function available(
        string $key,
        string $label,
        string $value,
        ?string $secondaryValue,
        string $targetUrl,
        string $targetKind,
        int $priority,
        string $actionLabel,
        ?string $contextBadge = null,
    ): self {
        return new self(
            key: $key,
            label: $label,
            value: $value,
            secondaryValue: $secondaryValue,
            targetUrl: $targetUrl,
            targetKind: $targetKind,
            availability: 'available',
            unavailableReason: null,
            contextBadge: $contextBadge,
            priority: $priority,
            actionLabel: $actionLabel,
            reference: null,
        );
    }

    public static function unavailable(
        string $key,
        string $label,
        UnavailableRelationState $state,
        string $targetKind,
        int $priority,
        string $actionLabel,
    ): self {
        return new self(
            key: $key,
            label: $label,
            value: 'Unavailable',
            secondaryValue: $state->showReference ? $state->referenceValue : null,
            targetUrl: null,
            targetKind: $targetKind,
            availability: $state->reason,
            unavailableReason: $state->message,
            contextBadge: null,
            priority: $priority,
            actionLabel: $actionLabel,
            reference: null,
        );
    }

    /**
     * @param  array{
     *   primaryLabel: string,
     *   secondaryLabel: ?string,
     *   state: string,
     *   stateDescription: ?string,
     *   linkTarget: array{targetKind: string, url: string, actionLabel: string, contextBadge: ?string}|null,
     *   technicalDetail: array{displayId: ?string, fullId: string, sourceHint: ?string, copyable: bool, defaultCollapsed: bool},
     *   isLinkable: bool
     * }&array<string, mixed>  $reference
     */
    public static function fromResolvedReference(
        string $key,
        string $label,
        string $targetKind,
        int $priority,
        string $actionLabel,
        array $reference,
    ): self {
        $linkTarget = is_array($reference['linkTarget'] ?? null) ? $reference['linkTarget'] : null;
        $technicalDetail = is_array($reference['technicalDetail'] ?? null) ? $reference['technicalDetail'] : [];
        $isLinkable = ($reference['isLinkable'] ?? false) === true
            && is_string($linkTarget['url'] ?? null)
            && $linkTarget['url'] !== '';

        $secondaryValueParts = array_values(array_filter([
            is_string($reference['secondaryLabel'] ?? null) ? $reference['secondaryLabel'] : null,
            is_string($technicalDetail['displayId'] ?? null) ? 'ID '.$technicalDetail['displayId'] : null,
        ]));

        return new self(
            key: $key,
            label: $label,
            value: (string) ($reference['primaryLabel'] ?? 'Reference'),
            secondaryValue: $secondaryValueParts !== [] ? implode(' · ', $secondaryValueParts) : null,
            targetUrl: $isLinkable ? (string) $linkTarget['url'] : null,
            targetKind: $targetKind,
            availability: $isLinkable ? 'available' : (string) ($reference['state'] ?? 'unresolved'),
            unavailableReason: is_string($reference['stateDescription'] ?? null) ? $reference['stateDescription'] : null,
            contextBadge: is_string($linkTarget['contextBadge'] ?? null) ? $linkTarget['contextBadge'] : null,
            priority: $priority,
            actionLabel: is_string($linkTarget['actionLabel'] ?? null) ? (string) $linkTarget['actionLabel'] : $actionLabel,
            reference: $reference,
        );
    }

    public function isAvailable(): bool
    {
        return $this->availability === 'available' && is_string($this->targetUrl) && $this->targetUrl !== '';
    }

    /**
     * @return array{
     *     key: string,
     *     label: string,
     *     value: string,
     *     secondaryValue: ?string,
     *     targetUrl: ?string,
     *     targetKind: string,
     *     availability: string,
     *     unavailableReason: ?string,
     *     contextBadge: ?string,
     *     priority: int,
     *     actionLabel: string,
     *     reference: array<string, mixed>|null
     * }
     */
    public function toArray(): array
    {
        return [
            'key' => $this->key,
            'label' => $this->label,
            'value' => $this->value,
            'secondaryValue' => $this->secondaryValue,
            'targetUrl' => $this->targetUrl,
            'targetKind' => $this->targetKind,
            'availability' => $this->availability,
            'unavailableReason' => $this->unavailableReason,
            'contextBadge' => $this->contextBadge,
            'priority' => $this->priority,
            'actionLabel' => $this->actionLabel,
            'reference' => $this->reference,
        ];
    }
}
