<?php

declare(strict_types=1);

namespace App\Support\ReasonTranslation;

use InvalidArgumentException;

final readonly class NextStepOption
{
    public function __construct(
        public string $label,
        public string $kind,
        public ?string $destination = null,
        public bool $authorizationRequired = false,
        public string $scope = 'none',
    ) {
        $label = trim($this->label);
        $kind = trim($this->kind);
        $scope = trim($this->scope);

        if ($label === '') {
            throw new InvalidArgumentException('Next-step labels must not be empty.');
        }

        if (! in_array($kind, ['link', 'instruction', 'diagnostic_only'], true)) {
            throw new InvalidArgumentException('Unsupported next-step kind: '.$kind);
        }

        if (! in_array($scope, ['tenant', 'workspace', 'system', 'none'], true)) {
            throw new InvalidArgumentException('Unsupported next-step scope: '.$scope);
        }

        if ($kind === 'link' && trim((string) $this->destination) === '') {
            throw new InvalidArgumentException('Link next steps require a destination.');
        }
    }

    public static function link(
        string $label,
        string $destination,
        bool $authorizationRequired = true,
        string $scope = 'tenant',
    ): self {
        return new self(
            label: $label,
            kind: 'link',
            destination: $destination,
            authorizationRequired: $authorizationRequired,
            scope: $scope,
        );
    }

    public static function instruction(string $label, string $scope = 'none'): self
    {
        return new self(
            label: $label,
            kind: 'instruction',
            scope: $scope,
        );
    }

    public static function diagnosticOnly(string $label): self
    {
        return new self(
            label: $label,
            kind: 'diagnostic_only',
            scope: 'none',
        );
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public static function fromArray(array $data): ?self
    {
        $label = is_string($data['label'] ?? null) ? trim((string) $data['label']) : '';
        $kind = is_string($data['kind'] ?? null)
            ? trim((string) $data['kind'])
            : ((is_string($data['url'] ?? null) || is_string($data['destination'] ?? null)) ? 'link' : 'instruction');
        $destination = is_string($data['destination'] ?? null)
            ? trim((string) $data['destination'])
            : (is_string($data['url'] ?? null) ? trim((string) $data['url']) : null);
        $authorizationRequired = (bool) ($data['authorization_required'] ?? $data['authorizationRequired'] ?? false);
        $scope = is_string($data['scope'] ?? null) ? trim((string) $data['scope']) : 'none';

        if ($label === '') {
            return null;
        }

        return new self(
            label: $label,
            kind: $kind,
            destination: $destination !== '' ? $destination : null,
            authorizationRequired: $authorizationRequired,
            scope: $scope,
        );
    }

    /**
     * @param  array<int, array<string, mixed>>  $items
     * @return array<int, self>
     */
    public static function collect(array $items): array
    {
        $options = [];

        foreach ($items as $item) {
            if (! is_array($item)) {
                continue;
            }

            $option = self::fromArray($item);

            if ($option instanceof self) {
                $options[] = $option;
            }
        }

        return $options;
    }

    /**
     * @return array{
     *     label: string,
     *     kind: string,
     *     destination: ?string,
     *     authorization_required: bool,
     *     scope: string
     * }
     */
    public function toArray(): array
    {
        return [
            'label' => $this->label,
            'kind' => $this->kind,
            'destination' => $this->destination,
            'authorization_required' => $this->authorizationRequired,
            'scope' => $this->scope,
        ];
    }

    /**
     * @return array{label: string, url: string}
     */
    public function toLegacyArray(): array
    {
        return [
            'label' => $this->label,
            'url' => (string) $this->destination,
        ];
    }
}
