"""Dispatch Bitbucket user mirror webhooks and keep mirror targets in sync."""
from __future__ import annotations

from typing import Any, Optional

from sqlalchemy.ext.asyncio import AsyncSession

from src.domain.bitbucket_user_mirror.repository import ProjectUserBitbucketMirrorRepository


async def dispatch(db: AsyncSession, event: str, payload: dict[str, Any]) -> dict[str, Any]:
    repo = ProjectUserBitbucketMirrorRepository(db)
    current_name = _current_repo_full_name(payload)
    old_name = _old_repo_full_name(payload)

    if event == "repo:deleted":
        if not current_name:
            return {"action": "ignored", "reason": "no_repo_full_name", "event": event}
        count = await repo.disable_by_target_repo(
            current_name,
            "Bitbucket repository was deleted.",
        )
        return {"action": "repo_deleted", "repo": current_name, "mirrors_disabled": count}

    if event in {"repo:updated", "repo:transfer"}:
        if old_name and current_name and old_name != current_name:
            count = await repo.rename_target_repo(old_name, current_name)
            return {
                "action": "repo_path_updated",
                "old_repo": old_name,
                "new_repo": current_name,
                "mirrors_updated": count,
            }
        return {"action": "repo_update_noted", "repo": current_name, "event": event}

    if event == "repo:push":
        if not current_name:
            return {"action": "push_ignored", "reason": "no_repo_full_name"}
        mirrors = await repo.list_by_target_repo(current_name)
        return {"action": "push_noted", "repo": current_name, "mirror_count": len(mirrors)}

    return {"action": "ignored", "event": event}


def _current_repo_full_name(payload: dict[str, Any]) -> Optional[str]:
    repository = payload.get("repository") or {}
    raw = repository.get("full_name") or payload.get("full_name")
    if isinstance(raw, str) and raw.strip():
        return raw.strip()
    return None


def _old_repo_full_name(payload: dict[str, Any]) -> Optional[str]:
    changes = payload.get("changes") or {}
    full_name_change = changes.get("full_name")
    if isinstance(full_name_change, dict):
        old = full_name_change.get("old") or full_name_change.get("previous")
        if isinstance(old, str) and old.strip():
            return old.strip()
    old_repository = payload.get("old") or payload.get("previous") or {}
    raw = old_repository.get("full_name") if isinstance(old_repository, dict) else None
    if isinstance(raw, str) and raw.strip():
        return raw.strip()
    return None
