<?php

declare(strict_types=1);



class AnnouncementService
{
    private const CACHE_KEY     = 'announce_cache';
    private const CACHE_AT      = 'announce_cache_at';
    private const FETCH_AT      = 'announce_fetch_at';
    private const TTL           = 15;
    private const MIN_RETRY     = 10;
    private const TIMEOUT       = 4;
    private const DEFAULT_COLOR = '#dc2626';

     
    public static function cached(): array
    {
        try {
            $raw = self::kvGet(self::CACHE_KEY);
            if ($raw === '') {
                return [];
            }
            $list = json_decode($raw, true);
            return is_array($list) ? $list : [];
        } catch (\Throwable $e) {
            return [];
        }
    }

    

    public static function refreshAndGet(): array
    {
        try {
            $now      = time();
            $cachedAt = (int) self::kvGet(self::CACHE_AT, '0');
            $fetchAt  = (int) self::kvGet(self::FETCH_AT, '0');

            if (($now - $cachedAt) >= self::TTL && ($now - $fetchAt) >= self::MIN_RETRY) {
                self::kvSet(self::FETCH_AT, (string) $now);
                $fresh = self::fetchRemote();
                if ($fresh !== null) {
                    self::kvSet(self::CACHE_KEY, json_encode($fresh, JSON_UNESCAPED_UNICODE));
                    self::kvSet(self::CACHE_AT, (string) $now);
                    return $fresh;
                }
            }
        } catch (\Throwable $e) {
             
        }
        return self::cached();
    }

    private static function fetchRemote(): ?array
    {
        if (!function_exists('curl_init')) {
            return null;
        }
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            => self::feedUrl(),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CONNECTTIMEOUT => self::TIMEOUT,
            CURLOPT_TIMEOUT        => self::TIMEOUT,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS      => 2,
            CURLOPT_USERAGENT      => 'TubePressCMS-Announce/1.0',
        ]);
        $body = curl_exec($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if (!is_string($body) || $code !== 200) {
            return null;
        }
        $data = json_decode($body, true);
        if (!is_array($data) || !isset($data['announcements']) || !is_array($data['announcements'])) {
            return null;
        }

        $out = [];
        foreach (array_slice($data['announcements'], 0, 20) as $a) {
            if (!is_array($a) || empty($a['message'])) {
                continue;
            }
            $link = (isset($a['link_url']) && preg_match('#^https?://#i', (string) $a['link_url']))
                ? mb_substr((string) $a['link_url'], 0, 500) : null;
            $out[] = [
                'id'         => (int) ($a['id'] ?? 0),
                'v'          => (int) ($a['v'] ?? 0),
                'color'      => self::normalizeColor((string) ($a['color'] ?? '')),
                'message'    => mb_substr((string) $a['message'], 0, 500),
                'link_url'   => $link,
                'link_label' => (isset($a['link_label']) && $a['link_label'] !== '') ? mb_substr((string) $a['link_label'], 0, 80) : null,
            ];
        }
        return $out;
    }

     
    public static function renderBar(array $list): string
    {
        $html = '';
        foreach ($list as $a) {
            $s   = self::shade((string) ($a['color'] ?? self::DEFAULT_COLOR));
            $msg = htmlspecialchars((string) ($a['message'] ?? ''), ENT_QUOTES, 'UTF-8');

            $link = '';
            if (!empty($a['link_url']) && preg_match('#^https?://#i', (string) $a['link_url'])) {
                $u   = htmlspecialchars((string) $a['link_url'], ENT_QUOTES, 'UTF-8');
                $lbl = htmlspecialchars((string) (($a['link_label'] ?? '') !== '' ? $a['link_label'] : 'Learn more'), ENT_QUOTES, 'UTF-8');
                $link = ' <a href="' . $u . '" target="_blank" rel="noopener noreferrer" style="color:' . $s['text'] . ';font-weight:700;text-decoration:underline">' . $lbl . ' &rarr;</a>';
            }

            $html .= '<div class="tpann" style="display:flex;align-items:center;gap:8px;padding:7px 16px;font-size:12px;line-height:1.4;border-bottom:1px solid ' . $s['border'] . ';background:' . $s['bg'] . ';color:' . $s['text'] . '">'
                  . '<i class="fa-solid fa-circle-info" style="flex-shrink:0;color:' . $s['accent'] . '"></i>'
                  . '<span style="min-width:0">' . $msg . $link . '</span>'
                  . '</div>';
        }
        return $html;
    }

     
    public static function signature(array $list): string
    {
        $parts = [];
        foreach ($list as $a) {
            $parts[] = (int) ($a['id'] ?? 0) . ':' . (int) ($a['v'] ?? 0);
        }
        return implode(',', $parts);
    }

     
    private static function shade(string $hex): array
    {
        $hex = ltrim(trim($hex), '#');
        if (strlen($hex) !== 6 || !ctype_xdigit($hex)) {
            $hex = ltrim(self::DEFAULT_COLOR, '#');
        }
        $r = hexdec(substr($hex, 0, 2));
        $g = hexdec(substr($hex, 2, 2));
        $b = hexdec(substr($hex, 4, 2));
        $d = static fn(int $c): int => (int) round($c * 0.5);
        return [
            'bg'     => "rgba($r,$g,$b,0.12)",
            'border' => "rgba($r,$g,$b,0.45)",
            'accent' => "#$hex",
            'text'   => sprintf('#%02x%02x%02x', $d($r), $d($g), $d($b)),
        ];
    }

    private static function normalizeColor(string $c): string
    {
        $c = trim($c);
        return preg_match('/^#[0-9a-fA-F]{6}$/', $c) ? strtolower($c) : self::DEFAULT_COLOR;
    }

    private static function feedUrl(): string
    {
        $base = (string) Setting::get('catalogue_api_url', '');
        if ($base === '') {
            $base = 'https://tubepress.io/v1';
        }
        return rtrim($base, '/') . '/public/announcements';
    }

    private static function kvGet(string $key, string $default = ''): string
    {
        $row = Database::fetchOne('SELECT setting_value FROM settings WHERE setting_key = ?', [$key]);
        return $row !== null ? (string) $row['setting_value'] : $default;
    }

    private static function kvSet(string $key, string $value): void
    {
        try {
            Database::query(
                'INSERT INTO settings (setting_key, setting_value, autoload) VALUES (?, ?, 0)
                 ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)',
                [$key, $value]
            );
        } catch (\Throwable $e) {
             
        }
    }
}
