"""Mirror a public git repository into Forgejo."""

from typing import Any

import httpx
from flowire_sdk import BaseNode, BaseNodeOutput, InputField, NodeExecutionContext, NodeMetadata, validate_url
from pydantic import BaseModel, Field

from fw_nodes_forgejo.credentials import ForgejoCredentialSchema


class MirrorRepoInput(BaseModel):
    credential_id: str = InputField(..., description="Forgejo credential")
    clone_url: str = InputField(
        ...,
        description="URL of the public repository to mirror (e.g., https://github.com/user/repo.git)",
    )
    repo_name: str = InputField(..., description="Name for the mirrored repository in Forgejo")
    repo_owner: str = InputField(
        default="",
        description="Organization or user to own the repo. Leave empty to use the authenticated user.",
    )
    description: str = InputField(default="", description="Repository description")
    private: bool = InputField(default=False, description="Make the mirrored repository private")
    mirror_interval: str = InputField(
        default="8h0m0s",
        description="How often to sync from upstream (e.g., 8h0m0s, 24h0m0s). Set to 0 to disable periodic sync.",
    )
    wiki: bool = InputField(default=False, description="Mirror the wiki")
    issues: bool = InputField(default=False, description="Mirror issues (only for supported services)")
    labels: bool = InputField(default=False, description="Mirror labels (only for supported services)")
    pull_requests: bool = InputField(default=False, description="Mirror pull requests (only for supported services)")
    releases: bool = InputField(default=False, description="Mirror releases (only for supported services)")


class MirrorRepoOutput(BaseNodeOutput):
    repo_id: int = Field(..., description="ID of the created repository")
    full_name: str = Field(..., description="Full name of the repository (owner/name)")
    html_url: str = Field(..., description="URL to view the repository in Forgejo")
    clone_url: str = Field(..., description="Git clone URL for the mirrored repository")
    mirror: bool = Field(..., description="Whether the repository is a mirror")
    success: bool = Field(..., description="Whether the mirror was created successfully")


class ForgejoMirrorRepoNode(BaseNode):
    """Mirror a public git repository into a Forgejo instance."""

    input_schema = MirrorRepoInput
    output_schema = MirrorRepoOutput
    credential_schema = ForgejoCredentialSchema

    metadata = NodeMetadata(
        name="Forgejo Mirror Repo",
        description="Mirror a public git repository into Forgejo",
        category="forgejo",
        icon="git-fork",
        color="#FF5500",
    )

    async def execute_logic(
        self,
        validated_inputs: dict[str, Any],
        context: NodeExecutionContext,
    ) -> MirrorRepoOutput:
        credential_data = await context.resolve_credential(
            credential_id=validated_inputs["credential_id"],
            credential_type=self.get_credential_type(),
        )

        server_url = credential_data["server_url"].rstrip("/")
        api_token = credential_data["api_token"]
        context.register_secret(api_token)

        validate_url(server_url)
        validate_url(validated_inputs["clone_url"])

        payload: dict[str, Any] = {
            "clone_addr": validated_inputs["clone_url"],
            "repo_name": validated_inputs["repo_name"],
            "mirror": True,
            "mirror_interval": validated_inputs["mirror_interval"],
            "private": validated_inputs["private"],
            "description": validated_inputs["description"],
            "service": "git",
            "wiki": validated_inputs["wiki"],
            "issues": validated_inputs["issues"],
            "labels": validated_inputs["labels"],
            "pull_requests": validated_inputs["pull_requests"],
            "releases": validated_inputs["releases"],
        }

        if validated_inputs.get("repo_owner"):
            payload["repo_owner"] = validated_inputs["repo_owner"]

        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{server_url}/api/v1/repos/migrate",
                headers={
                    "Authorization": f"token {api_token}",
                    "Content-Type": "application/json",
                },
                json=payload,
                timeout=120,
            )

        if response.status_code not in (200, 201):
            try:
                error_detail = response.json().get("message", response.text)
            except Exception:
                error_detail = response.text
            raise RuntimeError(f"Forgejo API error ({response.status_code}): {error_detail}")

        data = response.json()

        return MirrorRepoOutput(
            repo_id=data["id"],
            full_name=data["full_name"],
            html_url=data["html_url"],
            clone_url=data["clone_url"],
            mirror=data.get("mirror", True),
            success=True,
        )
