<?php

declare(strict_types=1);

namespace App\Tag;

/**
 * Central definition of all supported tag types.
 *
 * This class is intentionally tiny and dependency-free because it is the
 * foundation for entity validation, admin forms, routing, and catalog logic.
 */
final class TagTypes
{
    public const GENERIC = 'generic';
    public const CATALOG_ENTITY = 'catalog_entity';
    public const SALES_SIGNAL = 'sales_signal';

    /**
     * Returns the canonical list of allowed type values.
     *
     * @return list<string>
     */
    public static function all(): array
    {
        return [
            self::GENERIC,
            self::CATALOG_ENTITY,
            self::SALES_SIGNAL,
        ];
    }

    /**
     * Returns UI choices for forms and admin screens.
     *
     * @return array<string, string>
     */
    public static function choices(): array
    {
        return [
            'Generic' => self::GENERIC,
            'Catalog Entity' => self::CATALOG_ENTITY,
            'Sales Signal' => self::SALES_SIGNAL,
        ];
    }

    /**
     * Returns true if the given value is an allowed tag type.
     */
    public static function isValid(?string $type): bool
    {
        if ($type === null) {
            return false;
        }

        return in_array(self::normalize($type), self::all(), true);
    }

    /**
     * Normalizes external input into a canonical internal value.
     *
     * Empty or unknown input falls back to the provided default.
     */
    public static function normalize(?string $type, string $default = self::GENERIC): string
    {
        $type = mb_strtolower(trim((string) $type));
        $default = mb_strtolower(trim($default));

        if ($type === '') {
            return self::isKnownDefault($default) ? $default : self::GENERIC;
        }

        if (in_array($type, self::all(), true)) {
            return $type;
        }

        return self::isKnownDefault($default) ? $default : self::GENERIC;
    }

    /**
     * Returns a human-readable label for a canonical type.
     */
    public static function labelFor(string $type): string
    {
        return array_flip(self::choices())[self::normalize($type)] ?? 'Generic';
    }

    private static function isKnownDefault(string $type): bool
    {
        return in_array($type, self::all(), true);
    }

    private function __construct()
    {
    }
}