<?php
namespace Crawl\Repositories;

use Crawl\Lib\Database;

class CrawlQueueRepository
{
    private Database $db;

    public function __construct()
    {
        $this->db = Database::getInstance();
    }

    public function enqueue(int $runId, string $url, string $normalizedUrl, int $depth): void
    {
        $this->db->query(
            'INSERT IGNORE INTO crawl_queue (crawl_run_id, url, normalized_url, depth, status, attempts, created_at, updated_at)
             VALUES (?, ?, ?, ?, \'pending\', 0, NOW(), NOW())',
            [$runId, $url, $normalizedUrl, $depth]
        );
    }

    public function claimBatch(int $runId, int $limit): array
    {
        $this->db->pdo()->beginTransaction();
        try {
            $rows = $this->db->fetchAll(
                'SELECT id, url, normalized_url, depth, attempts FROM crawl_queue
                 WHERE crawl_run_id = ? AND status = \'pending\'
                 ORDER BY id ASC
                 LIMIT ' . (int)$limit . ' FOR UPDATE',
                [$runId]
            );

            if (!empty($rows)) {
                $ids = array_map(static fn(array $r): int => (int)$r['id'], $rows);
                $in = implode(',', $ids);
                $this->db->query("UPDATE crawl_queue SET status='processing', updated_at=NOW() WHERE id IN ({$in})");
            }

            $this->db->pdo()->commit();
            return $rows;
        } catch (\Throwable $e) {
            $this->db->pdo()->rollBack();
            throw $e;
        }
    }

    public function markDone(int $queueId): void
    {
        $this->db->query('UPDATE crawl_queue SET status = \'done\', updated_at = NOW() WHERE id = ?', [$queueId]);
    }

    public function markFailed(int $queueId, string $error): void
    {
        $this->db->query(
            'UPDATE crawl_queue SET status = \'failed\', attempts = attempts + 1, last_error = ?, updated_at = NOW() WHERE id = ?',
            [substr($error, 0, 1000), $queueId]
        );
    }

    public function pendingCount(int $runId): int
    {
        $row = $this->db->fetch('SELECT COUNT(*) AS cnt FROM crawl_queue WHERE crawl_run_id = ? AND status IN (\'pending\',\'processing\')', [$runId]);
        return (int)($row['cnt'] ?? 0);
    }
}

