"""Unit tests for the Gitea webhook parser.

Pure-function tests against ``parse_webhook`` using realistic Gitea
payloads (trimmed to the fields the parser actually consumes). No DB or
HTTP fixtures needed.
"""

from __future__ import annotations

from notify_bridge_core.models.events import EventType
from notify_bridge_core.providers.base import ServiceProviderType
from notify_bridge_core.providers.gitea.event_parser import parse_webhook


def _repo() -> dict:
    return {
        "id": 42,
        "name": "demo",
        "full_name": "alexei/demo",
        "html_url": "https://git.example.com/alexei/demo",
        "description": "Demo repo",
        "private": False,
        "owner": {
            "id": 1,
            "login": "alexei",
            "full_name": "Alexei",
            "email": "alexei@example.com",
            "avatar_url": "https://git.example.com/avatars/1",
        },
    }


def _sender() -> dict:
    return {
        "id": 1,
        "login": "alexei",
        "full_name": "Alexei",
        "avatar_url": "https://git.example.com/avatars/1",
    }


def test_push_event() -> None:
    payload = {
        "ref": "refs/heads/master",
        "before": "0000000000000000000000000000000000000000",
        "after": "abcdef0123456789abcdef0123456789abcdef01",
        "compare_url": "https://git.example.com/alexei/demo/compare/000...abc",
        "commits": [
            {
                "id": "abcdef0123456789abcdef0123456789abcdef01",
                "message": "feat: initial commit\n\nMore detail.",
                "url": "https://git.example.com/alexei/demo/commit/abcdef0",
                "author": {
                    "name": "Alexei",
                    "email": "alexei@example.com",
                    "username": "alexei",
                },
                "timestamp": "2026-05-16T10:00:00Z",
            },
            {
                "id": "1234567890123456789012345678901234567890",
                "message": "chore: tweak",
                "url": "https://git.example.com/alexei/demo/commit/1234567",
                "author": {"name": "Alexei", "email": "alexei@example.com"},
                "timestamp": "2026-05-16T10:05:00Z",
            },
        ],
        "repository": _repo(),
        "sender": _sender(),
    }

    evt = parse_webhook("push", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.PUSH
    assert evt.provider_type is ServiceProviderType.GITEA
    assert evt.collection_id == "alexei/demo"
    assert evt.collection_name == "alexei/demo"
    assert evt.extra["ref"] == "refs/heads/master"
    assert evt.extra["branch"] == "master"
    assert evt.extra["commit_count"] == 2
    assert evt.extra["commits"][0]["short_id"] == "abcdef0"
    # The first commit's multi-line body must be preserved (.strip handles
    # trailing newlines but should keep the inner '\n').
    assert "feat: initial commit" in evt.extra["commits"][0]["message"]


def test_issue_opened() -> None:
    payload = {
        "action": "opened",
        "issue": {
            "id": 100,
            "number": 7,
            "title": "Bug: thing broken",
            "html_url": "https://git.example.com/alexei/demo/issues/7",
            "state": "open",
            "body": "Steps to reproduce...",
            "labels": [{"name": "bug"}, {"name": "p1"}],
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("issues", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.ISSUE_OPENED
    assert evt.collection_id == "alexei/demo"
    assert evt.extra["issue_number"] == 7
    assert evt.extra["issue_title"] == "Bug: thing broken"
    assert evt.extra["issue_labels"] == ["bug", "p1"]


def test_issue_closed() -> None:
    payload = {
        "action": "closed",
        "issue": {
            "id": 100,
            "number": 7,
            "title": "Bug: thing broken",
            "html_url": "https://git.example.com/alexei/demo/issues/7",
            "state": "closed",
            "body": "",
            "labels": [],
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("issues", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.ISSUE_CLOSED
    assert evt.extra["issue_state"] == "closed"


def test_pr_opened() -> None:
    payload = {
        "action": "opened",
        "pull_request": {
            "id": 200,
            "number": 12,
            "title": "Add metrics endpoint",
            "html_url": "https://git.example.com/alexei/demo/pulls/12",
            "state": "open",
            "body": "PR body",
            "merged": False,
            "base": {"ref": "master", "label": "alexei:master"},
            "head": {"ref": "feat/metrics", "label": "alexei:feat/metrics"},
            "labels": [{"name": "enhancement"}],
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("pull_request", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.PR_OPENED
    assert evt.extra["pr_number"] == 12
    assert evt.extra["pr_merged"] is False
    assert evt.extra["pr_base"] == "alexei:master"
    assert evt.extra["pr_head"] == "alexei:feat/metrics"


def test_pr_merged_resolves_from_closed_with_merged_flag() -> None:
    """A 'closed' action with merged=True is the merge signal — Gitea does
    not send a distinct event header for it, so the parser must promote
    PR_CLOSED -> PR_MERGED on its own."""
    payload = {
        "action": "closed",
        "pull_request": {
            "id": 200,
            "number": 12,
            "title": "Add metrics endpoint",
            "html_url": "https://git.example.com/alexei/demo/pulls/12",
            "state": "closed",
            "body": "",
            "merged": True,
            "base": {"ref": "master"},
            "head": {"ref": "feat/metrics"},
            "labels": [],
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("pull_request", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.PR_MERGED
    assert evt.extra["pr_merged"] is True


def test_pr_closed_without_merge() -> None:
    payload = {
        "action": "closed",
        "pull_request": {
            "id": 200,
            "number": 12,
            "title": "Abandoned PR",
            "html_url": "https://git.example.com/alexei/demo/pulls/12",
            "state": "closed",
            "body": "",
            "merged": False,
            "base": {"ref": "master"},
            "head": {"ref": "feat/x"},
            "labels": [],
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("pull_request", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.PR_CLOSED


def test_release_published() -> None:
    payload = {
        "action": "published",
        "release": {
            "id": 9,
            "tag_name": "v1.2.3",
            "name": "Release v1.2.3",
            "html_url": "https://git.example.com/alexei/demo/releases/tag/v1.2.3",
            "body": "Bug fixes and improvements",
            "draft": False,
            "prerelease": False,
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    evt = parse_webhook("release", payload, provider_name="gitea-prod")
    assert evt is not None
    assert evt.event_type is EventType.RELEASE_PUBLISHED
    assert evt.extra["release_tag"] == "v1.2.3"
    assert evt.extra["release_prerelease"] is False


def test_release_non_published_is_ignored() -> None:
    """Only ``published`` releases should produce events — drafts and edits
    are noise and would spam any tracker subscribed to release notifications."""
    payload = {
        "action": "edited",
        "release": {
            "id": 9, "tag_name": "v1.2.3", "name": "x",
            "html_url": "", "body": "",
            "draft": True, "prerelease": False,
        },
        "repository": _repo(),
        "sender": _sender(),
    }
    assert parse_webhook("release", payload, provider_name="g") is None


def test_unknown_event_header_returns_none() -> None:
    payload = {"repository": _repo(), "sender": _sender()}
    assert parse_webhook("unknown_event", payload, provider_name="g") is None
