<?php
declare(strict_types=1);

namespace App\Avatar;

final class Lorelei
{
    public static function defaults(): array
    {
        return [
            'avatar_preset' => 'papa-kind-treff',
            'avatar_lorelei_eyes_variant' => '',
            'avatar_lorelei_eyebrows_variant' => '',
            'avatar_lorelei_mouth_variant' => '',
            'avatar_lorelei_glasses_variant' => '',
            'avatar_lorelei_hair_variant' => '',
            'avatar_lorelei_beard_variant' => '',
            'avatar_lorelei_earrings_variant' => '',
        ];
    }

    public static function options(): array
    {
        return [
            'avatar_lorelei_eyes_variant' => self::variantOptions(24),
            'avatar_lorelei_eyebrows_variant' => self::variantOptions(13),
            'avatar_lorelei_mouth_variant' => self::mouthVariantOptions(),
            'avatar_lorelei_glasses_variant' => ['' => 'Keine'] + self::variantOptions(5),
            'avatar_lorelei_hair_variant' => ['' => 'Keine'] + self::variantOptions(48),
            'avatar_lorelei_beard_variant' => ['' => 'Keine'] + self::variantOptions(2),
            'avatar_lorelei_earrings_variant' => ['' => 'Keine'] + self::variantOptions(3),
        ];
    }

    public static function componentDefinitions(): array
    {
        return [
            'avatar_lorelei_eyes_variant' => ['label' => 'Augen', 'auto' => false],
            'avatar_lorelei_eyebrows_variant' => ['label' => 'Augenbrauen', 'auto' => false],
            'avatar_lorelei_mouth_variant' => ['label' => 'Mund', 'auto' => false],
            'avatar_lorelei_glasses_variant' => ['label' => 'Brille', 'auto' => true],
            'avatar_lorelei_hair_variant' => ['label' => 'Haare', 'auto' => true],
            'avatar_lorelei_beard_variant' => ['label' => 'Bart', 'auto' => true],
            'avatar_lorelei_earrings_variant' => ['label' => 'Ohrringe', 'auto' => true],
        ];
    }

    public static function selectColumns(string $alias = 'p'): string
    {
        $columns = array_keys(self::defaults());
        return implode(', ', array_map(
            static fn(string $column): string => sprintf('%s.%s', $alias, $column),
            $columns
        ));
    }

    public static function normalize(array $input): array
    {
        $defaults = self::defaults();
        $normalized = [];

        foreach ($defaults as $key => $defaultValue) {
            $value = (string)($input[$key] ?? $defaultValue);
            if ($key === 'avatar_preset') {
                $normalized[$key] = self::normalizeSeed($value);
                continue;
            }

            if (str_starts_with($key, 'avatar_lorelei_')) {
                $normalized[$key] = self::normalizeVariant($value);
                continue;
            }

            $normalized[$key] = $value;
        }

        return $normalized;
    }

    public static function normalizeSeed(string $seed): string
    {
        $seed = strtolower(trim($seed));
        $seed = preg_replace('/[^a-z0-9]+/', '-', $seed) ?: '';
        $seed = trim($seed, '-');

        if ($seed === '') {
            $seed = self::defaults()['avatar_preset'];
        }

        return substr($seed, 0, 64);
    }

    public static function apiQuery(array $row): array
    {
        $avatar = self::normalize($row);
        $query = ['seed' => $avatar['avatar_preset']];
        $requiredMap = [
            'avatar_lorelei_eyes_variant' => 'eyesVariant',
            'avatar_lorelei_eyebrows_variant' => 'eyebrowsVariant',
            'avatar_lorelei_mouth_variant' => 'mouthVariant',
        ];
        $optionalMap = [
            'avatar_lorelei_glasses_variant' => ['variant' => 'glassesVariant', 'probability' => 'glassesProbability'],
            'avatar_lorelei_hair_variant' => ['variant' => 'hairVariant', 'probability' => 'hairProbability'],
            'avatar_lorelei_beard_variant' => ['variant' => 'beardVariant', 'probability' => 'beardProbability'],
            'avatar_lorelei_earrings_variant' => ['variant' => 'earringsVariant', 'probability' => 'earringsProbability'],
        ];

        foreach ($requiredMap as $key => $param) {
            if ($avatar[$key] !== '') {
                $query[$param] = $avatar[$key];
            }
        }

        foreach ($optionalMap as $key => $params) {
            if ($avatar[$key] === '') {
                $query[$params['probability']] = '0';
                continue;
            }

            $query[$params['variant']] = $avatar[$key];
            $query[$params['probability']] = '100';
        }

        return $query;
    }

    public static function buildProxyUrl(array $row): string
    {
        return '/api/avatar?' . http_build_query(self::apiQuery($row));
    }

    public static function previewChoices(array $row, string $field): array
    {
        $definitions = self::componentDefinitions();
        $options = self::options();
        $avatar = self::normalize($row);

        if (!isset($definitions[$field], $options[$field])) {
            return [];
        }

        $choices = [];
        foreach ($options[$field] as $value => $label) {
            $variantRow = $avatar;
            $variantRow[$field] = (string) $value;
            $choices[] = [
                'value' => (string) $value,
                'label' => (string) $label,
                'image' => self::buildProxyUrl($variantRow),
                'checked' => $avatar[$field] === (string) $value,
            ];
        }

        return $choices;
    }

    public static function render(array $row, string $name = 'Mitglied', string $size = 'md'): string
    {
        $avatar = self::normalize($row);
        $src = self::buildProxyUrl($avatar);

        return sprintf(
            '<span class="%s" role="img" aria-label="%s"><img class="pkt-avatar__img" src="%s" alt=""></span>',
            htmlspecialchars(implode(' ', [
                'pkt-avatar',
                'pkt-avatar--' . preg_replace('/[^a-z0-9\-]/', '', strtolower($size)),
                'pkt-avatar--generated',
            ]), ENT_QUOTES),
            htmlspecialchars('Avatar von ' . $name, ENT_QUOTES),
            htmlspecialchars($src, ENT_QUOTES)
        );
    }

    public static function fallbackSvg(string $seed, string $label = 'Avatar'): string
    {
        $seed = self::normalizeSeed($seed);
        $initials = strtoupper(substr(preg_replace('/[^a-z]/', '', $seed) ?: 'pk', 0, 2));
        $palette = ['#f5efe5', '#d9c7b3', '#8f6f54', '#37485a', '#c88f5b'];
        $hash = abs((int) crc32($seed));
        $bg = $palette[$hash % count($palette)];
        $fg = $hash % 2 === 0 ? '#243142' : '#ffffff';

        return sprintf(
            '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="%s"><rect width="128" height="128" rx="28" fill="%s"/><circle cx="64" cy="50" r="24" fill="rgba(255,255,255,0.26)"/><path d="M30 110c4-18 18-30 34-30s30 12 34 30" fill="rgba(255,255,255,0.2)"/><text x="64" y="76" text-anchor="middle" font-family="Arial, sans-serif" font-size="28" font-weight="700" fill="%s">%s</text></svg>',
            htmlspecialchars($label, ENT_QUOTES),
            htmlspecialchars($bg, ENT_QUOTES),
            htmlspecialchars($fg, ENT_QUOTES),
            htmlspecialchars($initials, ENT_QUOTES)
        );
    }

    private static function variantOptions(int $count): array
    {
        $options = [];
        for ($index = 1; $index <= $count; $index++) {
            $key = sprintf('variant%02d', $index);
            $options[$key] = 'Variante ' . $index;
        }

        return $options;
    }

    private static function mouthVariantOptions(): array
    {
        $options = [];

        for ($index = 1; $index <= 18; $index++) {
            $key = sprintf('happy%02d', $index);
            $options[$key] = 'Freundlich ' . $index;
        }

        for ($index = 1; $index <= 9; $index++) {
            $key = sprintf('sad%02d', $index);
            $options[$key] = 'Zurueckhaltend ' . $index;
        }

        return $options;
    }

    public static function normalizeVariant(string $value): string
    {
        $value = strtolower(trim($value));
        if ($value === '') {
            return '';
        }

        return preg_match('/^(variant\d{2}|happy\d{2}|sad\d{2})$/', $value) === 1 ? $value : '';
    }
}
