<?php

declare(strict_types=1);

namespace App\Services\Runbooks;

use Illuminate\Validation\ValidationException;

final readonly class RunbookReason
{
    public const string CODE_DATA_REPAIR = 'DATA_REPAIR';

    public const string CODE_INCIDENT = 'INCIDENT';

    public const string CODE_SUPPORT = 'SUPPORT';

    public const string CODE_SECURITY = 'SECURITY';

    public function __construct(
        public string $reasonCode,
        public string $reasonText,
    ) {
        $reasonCode = trim($this->reasonCode);
        $reasonText = trim($this->reasonText);

        if (! in_array($reasonCode, self::codes(), true)) {
            throw ValidationException::withMessages([
                'reason.reason_code' => 'Select a valid reason code.',
            ]);
        }

        if ($reasonText === '') {
            throw ValidationException::withMessages([
                'reason.reason_text' => 'Provide a reason.',
            ]);
        }

        if (mb_strlen($reasonText) > 500) {
            throw ValidationException::withMessages([
                'reason.reason_text' => 'Reason must be 500 characters or fewer.',
            ]);
        }
    }

    /**
     * @param  array<string, mixed>|null  $data
     */
    public static function fromNullableArray(?array $data): ?self
    {
        if (! is_array($data)) {
            return null;
        }

        $reasonCode = trim((string) ($data['reason_code'] ?? ''));
        $reasonText = trim((string) ($data['reason_text'] ?? ''));

        if ($reasonCode === '' && $reasonText === '') {
            return null;
        }

        return new self(
            reasonCode: $reasonCode,
            reasonText: $reasonText,
        );
    }

    /**
     * @return array<int, string>
     */
    public static function codes(): array
    {
        return [
            self::CODE_DATA_REPAIR,
            self::CODE_INCIDENT,
            self::CODE_SUPPORT,
            self::CODE_SECURITY,
        ];
    }

    /**
     * @return array<string, string>
     */
    public static function options(): array
    {
        return [
            self::CODE_DATA_REPAIR => 'Data repair',
            self::CODE_INCIDENT => 'Incident',
            self::CODE_SUPPORT => 'Support',
            self::CODE_SECURITY => 'Security',
        ];
    }

    /**
     * @return array{reason_code: string, reason_text: string}
     */
    public function toArray(): array
    {
        return [
            'reason_code' => trim($this->reasonCode),
            'reason_text' => trim($this->reasonText),
        ];
    }
}
