"""Tests for the extract-links subcommand."""

from __future__ import annotations

from pathlib import Path

import duckdb
import pytest

from suivi_seo.extract_links import extract_links, resolve_target, run


def _bootstrap_db(db_path: Path, slug: str, repo_path: Path, domain: str) -> None:
    """Create a minimal schema (sites + site_urls + internal_links) for tests."""
    con = duckdb.connect(str(db_path))
    con.execute(
        """
        CREATE TABLE sites (
            slug VARCHAR PRIMARY KEY,
            name VARCHAR,
            repo_path VARCHAR,
            domain VARCHAR
        );
        CREATE SEQUENCE seq_site_urls START 1;
        CREATE TABLE site_urls (
            id INTEGER PRIMARY KEY DEFAULT nextval('seq_site_urls'),
            site VARCHAR,
            url VARCHAR,
            slug VARCHAR,
            locale VARCHAR
        );
        CREATE SEQUENCE seq_internal_links START 1;
        CREATE TABLE internal_links (
            id INTEGER PRIMARY KEY DEFAULT nextval('seq_internal_links'),
            site VARCHAR,
            source_url_id INTEGER,
            target_url_id INTEGER,
            anchor_text VARCHAR,
            target_path VARCHAR,
            link_context VARCHAR,
            is_active BOOLEAN,
            UNIQUE(source_url_id, target_url_id, anchor_text)
        );
        """
    )
    con.execute(
        "INSERT INTO sites (slug, name, repo_path, domain) VALUES (?, ?, ?, ?)",
        [slug, slug, str(repo_path), domain],
    )
    con.close()


def test_extract_links_parses_internal_only() -> None:
    """Only `[anchor](/path)` should match; absolute URLs and fragments are ignored."""
    content = (
        "Voir le [guide SEO](/blog/seo/guide) et "
        "le [site externe](https://example.com) "
        "et la [section](#anchor) "
        "et l'[image](/images/photo.png) "
        "et l'[asset](/assets/file.pdf) "
        "et un [autre](/blog/audit)."
    )
    links = extract_links(content)
    paths = [p for _, p in links]
    assert paths == ["/blog/seo/guide", "/blog/audit"]


def test_resolve_target_handles_trailing_slash() -> None:
    """The url_map must accept both `/foo` and `/foo/` variants."""
    url_map = {
        "https://www.example.com/blog/seo/guide": 42,
        "https://www.example.com/blog/seo/guide/": 42,
    }
    assert resolve_target("/blog/seo/guide", "example.com", url_map) == 42
    assert resolve_target("/blog/seo/guide/", "example.com", url_map) == 42
    # Non-www should fall through to the without-www candidate too
    url_map2 = {"https://example.com/foo/": 7, "https://example.com/foo": 7}
    assert resolve_target("/foo", "example.com", url_map2) == 7


def test_run_fails_when_site_missing(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    """If the site slug is not present in `sites`, run() must exit non-zero."""
    db_path = tmp_path / "test.duckdb"
    # Bootstrap with a different site
    _bootstrap_db(db_path, slug="other", repo_path=tmp_path, domain="other.com")

    rc = run(slug="missing", db_path=db_path)
    assert rc == 1
    captured = capsys.readouterr()
    assert "missing" in captured.err
    assert "not found" in captured.err.lower()


def test_run_populates_internal_links(tmp_path: Path) -> None:
    """End-to-end: bootstrap a tiny repo + DB, run, check internal_links rows."""
    repo = tmp_path / "repo"
    blog = repo / "content" / "blog" / "fr"
    blog.mkdir(parents=True)
    (blog / "audit.mdx").write_text(
        "Lire le [guide](/blog/guide) ou [externe](https://x.com).\n",
        encoding="utf-8",
    )
    (blog / "guide.mdx").write_text(
        "Cf. l'[audit](/blog/audit).\n",
        encoding="utf-8",
    )

    db_path = tmp_path / "test.duckdb"
    _bootstrap_db(db_path, slug="demo", repo_path=repo, domain="demo.com")

    # Pre-populate site_urls so resolution works
    con = duckdb.connect(str(db_path))
    con.execute(
        "INSERT INTO site_urls (site, url, slug, locale) VALUES "
        "('demo', 'https://www.demo.com/blog/audit', 'audit', 'fr'),"
        "('demo', 'https://www.demo.com/blog/guide', 'guide', 'fr')"
    )
    con.close()

    rc = run(slug="demo", db_path=db_path)
    assert rc == 0

    con = duckdb.connect(str(db_path))
    rows = con.execute(
        "SELECT anchor_text, target_path, target_url_id IS NOT NULL "
        "FROM internal_links WHERE site = 'demo' ORDER BY anchor_text"
    ).fetchall()
    con.close()

    assert rows == [
        ("audit", "/blog/audit", True),
        ("guide", "/blog/guide", True),
    ]
