<?php

declare(strict_types=1);



class FrontAlbumController
{
    public static function routes(): void
    {
        Router::get('/albums', [self::class, 'index']);
        Router::get('/album/{slug}', [self::class, 'show']);
        Router::post('/album/{id}/favorite', [self::class, 'favorite']);
        Router::post('/album/{id}/like', [self::class, 'like']);
        Router::post('/album/{id}/dislike', [self::class, 'dislike']);
        Router::post('/album/{id}/comment', [self::class, 'comment']);
    }

     
    private static function ensureEnabled(bool $isPage = true): bool
    {
        if (Album::featureEnabled()) {
            return true;
        }
        http_response_code(410);
        if ($isPage) {
            ThemeRenderer::render('404');
        }
        return false;
    }

    public static function index(): void
    {
        if (!self::ensureEnabled()) { return; }
        $sort = $_GET['sort'] ?? Setting::get('albums_default_sort', 'newest');
        $perPage = (int) Setting::get('albums_per_page', '24');
        $videoType = Album::activeType();

        $search = trim((string) ($_GET['search'] ?? ''));
        $filters = ['sort' => $sort];
        if ($videoType !== '') $filters['video_type'] = $videoType;
        if ($search !== '') $filters['search'] = $search;

        $total = Album::count($filters);
        $pagination = Pagination::fromRequest($total, $perPage);
        $albums = Album::all($filters, $perPage, $pagination->offset);

        $prefix = ltrim(Router::langPrefix() . Router::typePrefix(), '/');
        $canonicalPath = $prefix !== '' ? $prefix . '/albums' : 'albums';
        $canonicalUrl = SEO::canonical($canonicalPath);
        $alternates = self::buildListAlternates('albums');
        Router::setAlternates($alternates);

        ThemeRenderer::render('albums', [
            'pageTitle' => SEO::title(__('page_title_albums')),
            'metaDescription' => __('page_title_albums'),
            'canonicalUrl' => $canonicalUrl,
            'alternates' => $alternates,
            'albums' => $albums,
            'pagination' => $pagination,
            'sort' => $sort,
            'search' => $search,
        ]);
    }

    public static function like(): void { self::handleAlbumVote('like'); }
    public static function dislike(): void { self::handleAlbumVote('dislike'); }

    private static function handleAlbumVote(string $type): void
    {
        if (!self::ensureEnabled(false)) { return; }
        if (!in_array($type, ['like', 'dislike'], true)) { Router::json(['error' => 'invalid_type'], 400); }
        if (!Router::verifyCsrf()) { Router::json(['error' => 'csrf_failed', 'message' => 'Your session has expired. Please refresh the page.'], 403); }
        if (!RateLimiter::throttle('vote', 60, 300)) { Router::json(['error' => 'rate_limit', 'message' => 'Too many votes. Please try again later.'], 429); }
        if (!Auth::check()) { Router::json(['error' => 'auth_required', 'message' => 'Please log in to perform this action.'], 401); }
        $albumId = (int) Router::param('id');
        $userId = Auth::id();
        $ip = RateLimiter::ip();
        $col = $type . 's';
        $existing = Database::fetchOne('SELECT type FROM album_likes WHERE user_id = ? AND album_id = ?', [$userId, $albumId]);
        if ($existing && $existing['type'] === $type) {
            Database::transaction(function () use ($userId, $albumId, $col) {
                Database::delete('album_likes', 'user_id = ? AND album_id = ?', [$userId, $albumId]);
                Database::query("UPDATE albums SET {$col} = GREATEST(0, {$col} - 1) WHERE id = ?", [$albumId]);
            });
            $userVote = null;
        } elseif ($existing) {
            $oldCol = in_array($existing['type'], ['like', 'dislike'], true) ? $existing['type'] . 's' : null;
            if ($oldCol) {
                Database::transaction(function () use ($userId, $albumId, $type, $ip, $oldCol, $col) {
                    Database::update('album_likes', ['type' => $type, 'ip_address' => $ip], 'user_id = ? AND album_id = ?', [$userId, $albumId]);
                    Database::query("UPDATE albums SET {$oldCol} = GREATEST(0, {$oldCol} - 1), {$col} = {$col} + 1 WHERE id = ?", [$albumId]);
                });
            }
            $userVote = $type;
        } else {
            Database::transaction(function () use ($userId, $albumId, $type, $ip, $col) {
                Database::insert('album_likes', ['user_id' => $userId, 'album_id' => $albumId, 'type' => $type, 'ip_address' => $ip]);
                Database::query("UPDATE albums SET {$col} = {$col} + 1 WHERE id = ?", [$albumId]);
            });
            $userVote = $type;
        }
        $a = Database::fetchOne('SELECT likes, dislikes FROM albums WHERE id = ?', [$albumId]);
        Router::json(['likes' => (int) $a['likes'], 'dislikes' => (int) $a['dislikes'], 'userVote' => $userVote]);
    }

    public static function comment(): void
    {
        if (!self::ensureEnabled(false)) { return; }
        $refPath = parse_url($_SERVER['HTTP_REFERER'] ?? '/', PHP_URL_PATH);
        $referer = ($refPath && $refPath[0] === '/' && ($refPath[1] ?? '') !== '/' && ord($refPath[1] ?? '') !== 92) ? $refPath : '/';
        $registrationEnabled = Setting::get('registration_enabled', '1') === '1';
        if ($registrationEnabled && !Auth::check()) { Router::redirect('/login'); }
        if (!Router::verifyCsrf()) { Router::redirect($referer); }
        $albumId = (int) Router::param('id');
        if (!Database::fetchOne('SELECT id FROM albums WHERE id = ?', [$albumId])) { Router::redirect($referer); }
        $body = trim($_POST['body'] ?? '');
        $ip = SpamGuard::ip();
        $spamError = SpamGuard::validate($body, $ip, $albumId, 'album_comment');
        if ($spamError !== null) { $_SESSION['flash'] = ['type' => 'error', 'message' => __($spamError)]; Router::redirect($referer); }
        if (!Captcha::verify('comment')) { $_SESSION['flash'] = ['type' => 'error', 'message' => __('error_captcha_failed')]; Router::redirect($referer); }
        $sanitizedBody = Sanitizer::text($body);
        $status = Setting::get('comments_moderation', '0') === '1' ? 'pending' : 'approved';
        $parentId = !empty($_POST['parent_id']) ? (int) $_POST['parent_id'] : null;
        if ($parentId !== null) {
            $parent = Comment::find($parentId);
            if (!$parent || (int) ($parent['album_id'] ?? 0) !== $albumId || $parent['parent_id'] !== null) { $parentId = null; }
        }
        $commentData = [
            'album_id'   => $albumId,
            'parent_id'  => $parentId,
            'body'       => $sanitizedBody,
            'body_hash'  => SpamGuard::bodyHash($body),
            'ip_address' => $ip,
            'status'     => $status,
        ];
        if (Auth::check()) { $commentData['user_id'] = Auth::id(); }
        else { $guestName = trim($_POST['guest_name'] ?? ''); $commentData['guest_name'] = $guestName !== '' ? Sanitizer::text($guestName) : 'Anonymous'; }
        Comment::create($commentData);
        Telegram::notifyComment(['pending' => (($commentData['status'] ?? '') === 'pending'), 'author' => Auth::check() ? (string) (Auth::user()['username'] ?? 'User') : (string) ($commentData['guest_name'] ?? 'Anonymous'), 'video_id' => 'album:' . $albumId, 'body' => $commentData['body'] ?? '']);
        Router::redirect($referer);
    }

    public static function show(): void
    {
        if (!self::ensureEnabled()) { return; }
        $album = Album::findBySlug(Router::param('slug'));
        if (!$album || ($album['status'] !== 'published' && !Auth::isAdmin())) {
            http_response_code(404);
            ThemeRenderer::render('404');
            return;
        }
        Router::enforceCanonicalType($album['video_type'], 'album', $album['slug']);

         
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $isBot = $ua === '' || strlen($ua) < 10
            || preg_match('/bot|crawl|spider|slurp|facebookexternalhit|Mediapartners|Baiduspider|yandex|sogou|exabot|ia_archiver|semrush|ahref|mj12bot|dotbot|petalbot|bytespider/i', $ua);
        if (!$isBot && HookSystem::applyFilter('album.should_increment_views', true, $album)) {
            Album::incrementViews((int) $album['id']);
        }

        $images = AlbumAsset::imageUrls($album);
        $relCount = max(0, min(24, (int) Setting::get('related_albums_count', '12')));
        $related = [];
        if ($relCount > 0) {
            $related = Album::similar((int) $album['id'], $relCount);
            if (count($related) < min(6, $relCount)) {
                $exclude = array_map('intval', array_column($related, 'id'));
                $related = array_merge($related, Album::recommended((int) $album['id'], $exclude, $relCount - count($related)));
            }
        }

         
        $type = $album['video_type'];
        $older = Database::fetchOne("SELECT slug, title FROM albums WHERE status='published' AND video_type=? AND id < ? ORDER BY id DESC LIMIT 1", [$type, (int) $album['id']]);
        $newer = Database::fetchOne("SELECT slug, title FROM albums WHERE status='published' AND video_type=? AND id > ? ORDER BY id ASC LIMIT 1", [$type, (int) $album['id']]);

        $isFavorited = false;
        $userVote = null;
        if (Auth::check()) {
            $isFavorited = (bool) Database::fetchOne('SELECT 1 FROM album_favorites WHERE user_id = ? AND album_id = ?', [Auth::id(), (int) $album['id']]);
            $uv = Database::fetchOne('SELECT type FROM album_likes WHERE user_id = ? AND album_id = ?', [Auth::id(), (int) $album['id']]);
            $userVote = $uv['type'] ?? null;
        }

         
        $prefix = ltrim(Router::langPrefix() . Router::typePrefix(), '/');
        $canonicalPath = $prefix !== '' ? $prefix . '/album/' . $album['slug'] : 'album/' . $album['slug'];
        $canonicalUrl = SEO::canonical($canonicalPath);
        $alternates = self::buildAlternates((int) $album['id']);
        Router::setAlternates($alternates);

        $description = !empty($album['description'])
            ? mb_substr(strip_tags($album['description']), 0, 160)
            : trim($album['title'] . ' — ' . (int) $album['image_count'] . ' ' . __('images'));
        $siteUrl = SEO::siteUrl();
        $coverUrl = AlbumAsset::coverUrl($album);
        $ogImage = $coverUrl !== '' ? (str_starts_with($coverUrl, 'http') ? $coverUrl : $siteUrl . $coverUrl) : '';

        $albumListPath = $prefix !== '' ? $prefix . '/albums' : 'albums';
        $breadcrumbJsonLd = SEO::breadcrumbJsonLd([
            ['name' => Setting::get('site_name', 'TubePress'), 'url' => $siteUrl . '/'],
            ['name' => __('page_title_albums'), 'url' => $siteUrl . '/' . $albumListPath],
            ['name' => $album['title'], 'url' => html_entity_decode($canonicalUrl)],
        ]);
        $jsonLd = $breadcrumbJsonLd;
        if (method_exists('SEO', 'imageGalleryJsonLd')) {
            $gallery = SEO::imageGalleryJsonLd($album, $images, html_entity_decode($canonicalUrl));
            if ($gallery !== '') $jsonLd = $breadcrumbJsonLd . "\n" . $gallery;
        }

        ThemeRenderer::render('album', [
            'pageTitle' => SEO::title($album['title']),
            'metaDescription' => $description,
            'canonicalUrl' => $canonicalUrl,
            'alternates' => $alternates,
            'ogTags' => [
                'og:title' => $album['title'],
                'og:description' => $description,
                'og:url' => $canonicalUrl,
                'og:image' => $ogImage,
                'og:type' => 'article',
            ],
            'twitterCard' => [
                'twitter:title' => $album['title'],
                'twitter:description' => $description,
                'twitter:image' => $ogImage,
            ],
            'jsonLd' => $jsonLd,
            'album' => $album,
            'images' => $images,
            'related' => $related,
            'prevAlbum' => $newer,  
            'nextAlbum' => $older,
            'isFavorited' => $isFavorited,
            'userVote' => $userVote,
            'comments' => Comment::forAlbum((int) $album['id']),
        ]);
    }

     
    public static function favorite(): void
    {
        if (!self::ensureEnabled(false)) { return; }
        if (!Auth::check()) {
            Router::json(['error' => 'auth_required'], 401);
            return;
        }
        if (!Router::verifyCsrf()) {
            Router::json(['error' => 'invalid_csrf'], 403);
            return;
        }
        $id = (int) Router::param('id');
        $album = Database::fetchOne('SELECT id FROM albums WHERE id = ? AND status = ?', [$id, 'published']);
        if (!$album) {
            Router::json(['error' => 'not_found'], 404);
            return;
        }
        $uid = Auth::id();
        $exists = Database::fetchOne('SELECT 1 FROM album_favorites WHERE user_id = ? AND album_id = ?', [$uid, $id]);
        if ($exists) {
            Database::delete('album_favorites', 'user_id = ? AND album_id = ?', [$uid, $id]);
            $favorited = false;
        } else {
            Database::query('INSERT IGNORE INTO album_favorites (user_id, album_id) VALUES (?, ?)', [$uid, $id]);
            $favorited = true;
        }
        Album::refreshFavoritesCount($id);
        $count = (int) (Database::fetchOne('SELECT favorites_count FROM albums WHERE id = ?', [$id])['favorites_count'] ?? 0);
        Router::json(['favorited' => $favorited, 'count' => $count]);
    }

    private static function buildAlternates(int $albumId): array
    {
        $base = Database::fetchOne('SELECT slug, video_type FROM albums WHERE id = ?', [$albumId]);
        if (!$base) return [];
        $siteUrl = SEO::siteUrl();
        $defaultLang = Translator::getDefaultCode();
        $typePrefix = Router::typePrefixFor($base['video_type']);
        $translations = Album::translations($albumId);
        $alternates = [];
        $alternates[$defaultLang] = $siteUrl . $typePrefix . '/album/' . $base['slug'];
        foreach (Translator::available() as $lang) {
            if ($lang['code'] === $defaultLang) continue;
            $slug = $translations[$lang['code']]['slug'] ?? $base['slug'];
            $alternates[$lang['code']] = $siteUrl . '/' . $lang['code'] . $typePrefix . '/album/' . $slug;
        }
        $alternates['x-default'] = $alternates[$defaultLang];
        return $alternates;
    }

    private static function buildListAlternates(string $route): array
    {
        $siteUrl = SEO::siteUrl();
        $defaultLang = Translator::getDefaultCode();
        $typePrefix = Router::typePrefix();
        $alternates = [];
        $alternates[$defaultLang] = $siteUrl . $typePrefix . '/' . $route;
        foreach (Translator::available() as $lang) {
            if ($lang['code'] === $defaultLang) continue;
            $alternates[$lang['code']] = $siteUrl . '/' . $lang['code'] . $typePrefix . '/' . $route;
        }
        $alternates['x-default'] = $alternates[$defaultLang];
        return $alternates;
    }
}
