<?php
namespace Crawl\Repositories;

use Crawl\Lib\Database;

class CrawlLinkRepository
{
    private Database $db;

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

    public function insertMany(int $runId, array $links): void
    {
        if (empty($links)) {
            return;
        }

        $sql = 'INSERT INTO crawl_links (crawl_run_id, from_url, to_url, anchor_text, link_context, is_internal, is_nofollow, created_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, NOW())';

        foreach ($links as $link) {
            $this->db->query($sql, [
                $runId,
                $link['from_url'],
                $link['to_url'],
                $link['anchor_text'],
                $link['link_context'] ?? 'Body',
                $link['is_internal'] ? 1 : 0,
                $link['is_nofollow'] ? 1 : 0,
            ]);
        }
    }

    public function inlinksForUrl(int $runId, string $url): array
    {
        return $this->db->fetchAll('SELECT * FROM crawl_links WHERE crawl_run_id = ? AND to_url = ? ORDER BY id DESC LIMIT 200', [$runId, $url]);
    }

    public function outlinksForUrl(int $runId, string $url): array
    {
        return $this->db->fetchAll('SELECT * FROM crawl_links WHERE crawl_run_id = ? AND from_url = ? ORDER BY id DESC LIMIT 200', [$runId, $url]);
    }

    public function orphanSample(int $runId, int $limit = 20): array
    {
        // Normalise trailing slash before comparing so /page and /page/ are treated the same.
        // Exclude depth-0 entry point — it has no inbound crawl links by definition.
        return $this->db->fetchAll(
            'SELECT p.url
             FROM crawl_pages p
             LEFT JOIN crawl_links l
               ON  l.crawl_run_id = p.crawl_run_id
               AND TRIM(TRAILING "/" FROM l.to_url) = TRIM(TRAILING "/" FROM p.url)
               AND l.is_internal = 1
             WHERE p.crawl_run_id = ?
               AND p.depth > 0
               AND l.id IS NULL
             ORDER BY p.depth ASC
             LIMIT ' . (int)$limit,
            [$runId]
        );
    }

    public function linkEquityMap(int $runId, int $limit, int $offset): array
    {
        return $this->db->fetchAll(
            "SELECT p.url, COUNT(l.id) AS inlink_count,
                    GROUP_CONCAT(DISTINCT l.anchor_text ORDER BY l.id DESC SEPARATOR '|||') AS anchors
             FROM crawl_pages p
             LEFT JOIN crawl_links l
               ON  l.crawl_run_id = p.crawl_run_id
               AND TRIM(TRAILING "/" FROM l.to_url) = TRIM(TRAILING "/" FROM p.url)
               AND l.is_internal = 1
             WHERE p.crawl_run_id = ? AND p.status_code = 200
             GROUP BY p.url
             ORDER BY inlink_count DESC
             LIMIT {$limit} OFFSET {$offset}",
            [$runId]
        );
    }

    public function orphanCount(int $runId): int
    {
        $row = $this->db->fetch(
            'SELECT COUNT(*) AS c FROM crawl_pages p
             LEFT JOIN crawl_links l
               ON  l.crawl_run_id = p.crawl_run_id
               AND TRIM(TRAILING "/" FROM l.to_url) = TRIM(TRAILING "/" FROM p.url)
               AND l.is_internal = 1
             WHERE p.crawl_run_id = ? AND p.depth > 0 AND l.id IS NULL',
            [$runId]
        );
        return (int)($row['c'] ?? 0);
    }

    public function anchorTextDistribution(int $runId, int $limit = 30): array
    {
        return $this->db->fetchAll(
            "SELECT anchor_text, COUNT(*) AS cnt
             FROM crawl_links
             WHERE crawl_run_id = ? AND is_internal = 1 AND anchor_text != ''
             GROUP BY anchor_text ORDER BY cnt DESC
             LIMIT {$limit}",
            [$runId]
        );
    }

    public function tabData(int $runId, string $tab, int $limit, int $offset): array
    {
        switch ($tab) {
            case 'inlinks':
                // Individual link records: who links to each page + from where
                return $this->db->fetchAll(
                    "SELECT
                        cl.from_url    AS source_url,
                        cl.to_url      AS destination_url,
                        cl.anchor_text,
                        cl.link_context AS location,
                        cl.is_nofollow
                     FROM crawl_links cl
                     WHERE cl.crawl_run_id = ? AND cl.is_internal = 1
                     ORDER BY cl.to_url, cl.from_url
                     LIMIT {$limit} OFFSET {$offset}",
                    [$runId]
                );
            case 'outlinks':
                // Individual link records: what each page links to + location of the link
                return $this->db->fetchAll(
                    "SELECT
                        cl.from_url    AS source_url,
                        cl.to_url      AS destination_url,
                        cl.anchor_text,
                        cl.link_context AS location,
                        cl.is_nofollow
                     FROM crawl_links cl
                     WHERE cl.crawl_run_id = ? AND cl.is_internal = 1
                     ORDER BY cl.from_url, cl.to_url
                     LIMIT {$limit} OFFSET {$offset}",
                    [$runId]
                );
            case 'external_links':
                return $this->db->fetchAll(
                    "SELECT from_url AS source_url, to_url AS destination_url, anchor_text, link_context AS location
                     FROM crawl_links
                     WHERE crawl_run_id = ? AND is_internal = 0
                     ORDER BY id DESC
                     LIMIT {$limit} OFFSET {$offset}",
                    [$runId]
                );
            default:
                return [];
        }
    }
}
