<?php
declare(strict_types=1);

namespace Celena\Module\Banners;

use Celena\Core\Database\Connection;

/**
 * Источник для блок-тега [banners ...]. Возвращает список баннеров,
 * подходящих под фильтры:
 *   - placement="hero"     — обязательный фильтр зоны (hero | sidebar | footer | popup или любая другая строка)
 *   - limit="N"            — сколько вернуть (по умолчанию 10, максимум 50)
 *   - sort="sort_order|id" — поле сортировки (по умолчанию sort_order ASC)
 *   - order="asc|desc"
 *   - active="1|0|all"     — по умолчанию 1 (только активные); all отдаёт всё для предпросмотра
 *
 * Автоматически фильтрует по starts_at / ends_at — если задано окно
 * показа, баннер выводится только в его пределах.
 *
 * Для каждого баннера в результат добавляются:
 *   - image / mobile_image — как пришли из БД
 *   - url, cta_label, subtitle — как есть
 *   - title — заголовок
 *   - has_image — '1' / '' (для условий в шаблонах)
 */
final class BannersContentSource
{
    private const ALLOWED_SORT = ['sort_order', 'id', 'created_at'];

    public function __construct(private readonly Connection $conn)
    {
    }

    /**
     * @param array<string, mixed> $params
     * @return array<int, array<string, mixed>>
     */
    public function fetch(array $params): array
    {
        $q = $this->conn->builder('celena_banners');

        $placement = trim((string) ($params['placement'] ?? ''));
        if ($placement !== '') {
            $q->where('placement', '=', $placement);
        }

        $active = strtolower((string) ($params['active'] ?? '1'));
        if ($active !== 'all') {
            $q->where('is_active', '=', $active === '0' ? false : true);
        }

        // Окно показа: starts_at <= now или null, ends_at >= now или null.
        $now = date('Y-m-d H:i:s');
        $startsCol = $this->conn->quoteId('starts_at');
        $endsCol   = $this->conn->quoteId('ends_at');
        $q->whereRaw("($startsCol IS NULL OR $startsCol <= ?)", [$now]);
        $q->whereRaw("($endsCol IS NULL OR $endsCol >= ?)", [$now]);

        $sort = (string) ($params['sort'] ?? 'sort_order');
        if (!in_array($sort, self::ALLOWED_SORT, true)) $sort = 'sort_order';
        $order = strtolower((string) ($params['order'] ?? 'asc')) === 'desc' ? 'desc' : 'asc';
        $q->orderBy($sort, $order);
        // Стабильный вторичный порядок при равных sort_order.
        if ($sort !== 'id') $q->orderBy('id', 'asc');

        $limit = (int) ($params['limit'] ?? 10);
        if ($limit < 1) $limit = 10;
        if ($limit > 50) $limit = 50;
        $q->limit($limit);

        $rows = $q->get();
        if ($rows === []) return [];

        foreach ($rows as &$r) {
            $r['image']        = (string) ($r['image'] ?? '');
            $r['mobile_image'] = (string) ($r['mobile_image'] ?? '');
            $r['url']          = (string) ($r['url'] ?? '');
            $r['title']        = (string) ($r['title'] ?? '');
            $r['subtitle']     = (string) ($r['subtitle'] ?? '');
            $r['cta_label']    = (string) ($r['cta_label'] ?? '');
            $r['has_image']    = $r['image'] !== '' ? '1' : '';
            $r['has_url']      = $r['url']   !== '' ? '1' : '';
        }
        unset($r);
        return $rows;
    }
}
