<?php
/**
 * Maps conversational content fields onto Bricks element settings.
 *
 * @package LolaCoreForBricks
 */

declare(strict_types=1);

namespace LolaCoreForBricks\Support;

/**
 * Shared content → settings translation for setElementContent and add* shortcuts.
 */
final class ElementContentMapper
{
    public function __construct(
        private readonly ?MediaLibraryResolver $media = null
    ) {
    }

    /**
     * Shortcuts must speak the schema. Top-level text/image/label is not a second grammar.
     *
     * @param array<string, mixed> $params
     * @return array{success: false, message: string, error: string}|null
     */
    public function shortcutContentGuard(string $elementName, array $params): ?array
    {
        $content = is_array($params['content'] ?? null) ? $params['content'] : [];

        if ($elementName === 'heading' || $elementName === 'text') {
            $text = trim((string) ($content['text'] ?? ''));
            if ($text === '') {
                return [
                    'success' => false,
                    'message' => 'I need the copy in content.text. I will not add an empty ' . $elementName . '.',
                    'error'   => 'missing_text',
                ];
            }
        }

        if ($elementName === 'image' && !$this->hasImageValue($content['image'] ?? null)) {
            return [
                'success' => false,
                'message' => 'I need an image from the Media Library in content.image. I will not add an empty image.',
                'error'   => 'missing_image',
            ];
        }

        if ($elementName === 'button') {
            $text = trim((string) ($content['text'] ?? ''));
            if ($text === '') {
                return [
                    'success' => false,
                    'message' => 'I need the button label in content.text. I will not add an empty button.',
                    'error'   => 'missing_label',
                ];
            }
        }

        return null;
    }

    /**
     * @param array<string, mixed> $content
     * @return array{success: true, settings: array<string, mixed>}|array{success: false, message: string, error: string}
     */
    public function toSettings(string $elementName, array $content): array
    {
        unset($elementName);
        $settings = [];

        if (array_key_exists('text', $content)) {
            $settings['text'] = (string) $content['text'];
        }

        if (array_key_exists('tag', $content)) {
            $settings['tag'] = sanitize_key((string) $content['tag']);
        }

        if (array_key_exists('link', $content)) {
            $settings['link'] = $this->normalizeLink($content['link']);
        }

        if (array_key_exists('alt', $content)) {
            $settings['alt'] = (string) $content['alt'];
        }

        if (array_key_exists('image', $content)) {
            $resolved = $this->media()->resolve($content['image']);
            if (($resolved['success'] ?? false) !== true) {
                return $resolved;
            }

            $settings['image'] = $resolved['image'];
        }

        return [
            'success'  => true,
            'settings' => $settings,
        ];
    }

    /**
     * @param mixed $link
     * @return array<string, mixed>
     */
    private function normalizeLink(mixed $link): array
    {
        if (is_string($link)) {
            return [
                'type' => 'external',
                'url'  => $link,
            ];
        }

        if (!is_array($link)) {
            return [];
        }

        $normalized = $link;
        if (!isset($normalized['type']) && isset($normalized['url'])) {
            $normalized['type'] = 'external';
        }

        return $normalized;
    }

    private function hasImageValue(mixed $image): bool
    {
        if ($image === null || $image === '' || $image === []) {
            return false;
        }

        if (is_array($image)) {
            return absint($image['id'] ?? 0) > 0 || trim((string) ($image['url'] ?? '')) !== '';
        }

        return true;
    }

    private function media(): MediaLibraryResolver
    {
        return $this->media ?? new MediaLibraryResolver();
    }
}
