<?php

namespace App\Blog\Service;

use App\Blog\Entity\Blog;

/**
 * Maps the SEO + scheduling fields of a blog write request onto the entity.
 * Shared by the admin BlogController and the representative RepresentationBlogController
 * so both accept the same field set without duplicating the mapping.
 *
 * Core fields (title/body/summary/tags/status/image/city) and ownership stay in
 * the controllers — this service is only the optional SEO/scheduling surface.
 */
class BlogWriter
{
    /** Apply any SEO / scheduling fields present in $data. Missing keys are left untouched. */
    public function applySeoFields(Blog $blog, array $data): void
    {
        if (array_key_exists('meta_title', $data))       $blog->setMetaTitle($this->str($data['meta_title']));
        if (array_key_exists('meta_description', $data))  $blog->setMetaDescription($this->str($data['meta_description']));
        if (array_key_exists('primary_keyword', $data))   $blog->setPrimaryKeyword($this->str($data['primary_keyword']));
        if (array_key_exists('secondary_keywords', $data)) $blog->setSecondaryKeywords($this->arr($data['secondary_keywords']));
        if (array_key_exists('faq', $data))               $blog->setFaq($this->faq($data['faq']));
        if (array_key_exists('internal_links', $data))    $blog->setInternalLinks($this->arr($data['internal_links']));
        if (array_key_exists('external_links', $data))    $blog->setExternalLinks($this->arr($data['external_links']));
        if (array_key_exists('reading_time', $data))      $blog->setReadingTime($this->int($data['reading_time']));
        if (array_key_exists('canonical_url', $data))     $blog->setCanonicalUrl($this->str($data['canonical_url']));
        if (array_key_exists('og_image', $data))          $blog->setOgImage($this->str($data['og_image']));
        if (array_key_exists('scheduled_at', $data))      $blog->setScheduledAt($this->int($data['scheduled_at']));
    }

    private function str(mixed $v): ?string
    {
        $v = is_string($v) ? trim($v) : $v;
        return ($v === null || $v === '') ? null : (string) $v;
    }

    private function int(mixed $v): ?int
    {
        return ($v === null || $v === '') ? null : (int) $v;
    }

    /** @return list<string> non-empty string values */
    private function arr(mixed $v): array
    {
        if (!is_array($v)) {
            return [];
        }
        return array_values(array_filter(array_map(
            fn($x) => is_string($x) ? trim($x) : $x,
            $v
        ), fn($x) => $x !== null && $x !== ''));
    }

    /** @return list<array{q:string,a:string}> — drops malformed entries. */
    private function faq(mixed $v): array
    {
        if (!is_array($v)) {
            return [];
        }
        $out = [];
        foreach ($v as $item) {
            if (is_array($item) && !empty($item['q']) && !empty($item['a'])) {
                $out[] = ['q' => trim((string) $item['q']), 'a' => trim((string) $item['a'])];
            }
        }
        return $out;
    }
}
