package top.r394realms.ltdmanagertest.gitea

import kotlinx.serialization.json.Json
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import top.r3944realms.ltdmanager.module.gitea.*

class GiteaEventTest {

    private val json = Json { ignoreUnknownKeys = true; coerceInputValues = true }

    // ====== GiteaEventType ======

    @Test
    fun `fromHeader parses all event types case-insensitively`() {
        assertEquals(GiteaEventType.PUSH, GiteaEventType.fromHeader("push"))
        assertEquals(GiteaEventType.PUSH, GiteaEventType.fromHeader("PUSH"))
        assertEquals(GiteaEventType.ISSUES, GiteaEventType.fromHeader("issues"))
        assertEquals(GiteaEventType.PULL_REQUEST, GiteaEventType.fromHeader("pull_request"))
        assertEquals(GiteaEventType.CREATE, GiteaEventType.fromHeader("create"))
        assertEquals(GiteaEventType.DELETE, GiteaEventType.fromHeader("delete"))
        assertEquals(GiteaEventType.RELEASE, GiteaEventType.fromHeader("release"))
        assertEquals(GiteaEventType.REPOSITORY, GiteaEventType.fromHeader("repository"))
        assertEquals(GiteaEventType.FORK, GiteaEventType.fromHeader("fork"))
    }

    @Test
    fun `fromHeader returns null for unknown event type`() {
        assertNull(GiteaEventType.fromHeader("unknown"))
        assertNull(GiteaEventType.fromHeader(""))
        assertNull(GiteaEventType.fromHeader(null))
    }

    @Test
    fun `fromHeader returns null for null input`() {
        assertNull(GiteaEventType.fromHeader(null))
    }

    // ====== PushPayload ======

    @Test
    fun `deserialize push payload`() {
        val payload = json.decodeFromString<PushPayload>(pushJson)
        assertEquals("refs/heads/master", payload.ref)
        assertEquals(2, payload.totalCommits)
        assertEquals("user/repo", payload.repository.fullName)
        assertEquals("alice", payload.sender.login)
        assertEquals(2, payload.commits.size)
        assertEquals("Fix bug", payload.commits[0].message)
        assertEquals("bob", payload.commits[0].author.login)
    }

    // ====== IssuesPayload ======

    @Test
    fun `deserialize issues payload`() {
        val payload = json.decodeFromString<IssuesPayload>(issuesJson)
        assertEquals("opened", payload.action)
        assertEquals(42, payload.issue.number)
        assertEquals("Bug report", payload.issue.title)
        assertEquals("open", payload.issue.state)
        assertEquals("alice", payload.issue.user.login)
        assertEquals("user/repo", payload.repository.fullName)
    }

    // ====== PullRequestPayload ======

    @Test
    fun `deserialize pull_request payload`() {
        val payload = json.decodeFromString<PullRequestPayload>(prJson)
        assertEquals("opened", payload.action)
        assertEquals(7, payload.number)
        assertEquals("feature", payload.pullRequest.headBranch.label)
        assertEquals("master", payload.pullRequest.baseBranch.label)
        assertEquals("open", payload.pullRequest.state)
        assertFalse(payload.pullRequest.merged)
    }

    // ====== CreatePayload ======

    @Test
    fun `deserialize create payload`() {
        val payload = json.decodeFromString<CreatePayload>(createJson)
        assertEquals("feature-x", payload.ref)
        assertEquals("branch", payload.refType)
        assertEquals("user/repo", payload.repository.fullName)
    }

    // ====== DeletePayload ======

    @Test
    fun `deserialize delete payload`() {
        val payload = json.decodeFromString<DeletePayload>(deleteJson)
        assertEquals("old-branch", payload.ref)
        assertEquals("branch", payload.refType)
    }

    // ====== ReleasePayload ======

    @Test
    fun `deserialize release payload`() {
        val payload = json.decodeFromString<ReleasePayload>(releaseJson)
        assertEquals("published", payload.action)
        assertEquals("v1.0.0", payload.release.tagName)
        assertEquals("First Release", payload.release.name)
        assertFalse(payload.release.draft)
        assertFalse(payload.release.prerelease)
    }

    // ====== RepositoryPayload ======

    @Test
    fun `deserialize repository payload`() {
        val payload = json.decodeFromString<RepositoryPayload>(repoJson)
        assertEquals("created", payload.action)
        assertEquals("user/new-repo", payload.repository.fullName)
    }

    // ====== ForkPayload ======

    @Test
    fun `deserialize fork payload`() {
        val payload = json.decodeFromString<ForkPayload>(forkJson)
        assertEquals("user/original", payload.repository.fullName)
        assertEquals("alice/original", payload.forkedRepo.fullName)
    }

    // ====== GiteaUser / GiteaRepository deserialization ======

    @Test
    fun `deserialize GiteaUser with login_name and full_name`() {
        val userJson = """{"id":1,"login":"octocat","login_name":"octocat","full_name":"Octo Cat","email":"octo@cat.com","avatar_url":"https://example.com/avatar.png","username":"octocat"}"""
        val user = json.decodeFromString<GiteaUser>(userJson)
        assertEquals(1L, user.id)
        assertEquals("octocat", user.login)
        assertEquals("octocat", user.loginName)
        assertEquals("Octo Cat", user.fullName)
        assertEquals("octo@cat.com", user.email)
    }

    @Test
    fun `deserialize GiteaRepository with defaults for null fields`() {
        val repoJson = """{"id":10,"name":"hello-world","full_name":"user/hello-world","html_url":"https://gitea.example.com/user/hello-world","default_branch":"main","private":false}"""
        val repo = json.decodeFromString<GiteaRepository>(repoJson)
        assertEquals(10L, repo.id)
        assertEquals("hello-world", repo.name)
        assertEquals("user/hello-world", repo.fullName)
        assertEquals("main", repo.defaultBranch)
        assertEquals("", repo.description)
    }

    // ====== Sample JSON payloads (from Gitea webhook docs) ======

    companion object {
        val pushJson = """
        {
          "ref": "refs/heads/master",
          "before": "abc123",
          "after": "def456",
          "compare_url": "https://gitea.example.com/user/repo/compare/abc123...def456",
          "commits": [
            {"id": "abc123def456789", "message": "Fix bug", "url": "", "author": {"id":1,"login":"bob","login_name":"bob","full_name":"Bob","email":"bob@bob.com","avatar_url":"","username":"bob"}, "committer": {"id":1,"login":"bob","login_name":"bob","full_name":"Bob","email":"bob@bob.com","avatar_url":"","username":"bob"}, "timestamp": ""},
            {"id": "def456abc789", "message": "Add feature", "url": "", "author": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"alice@a.com","avatar_url":"","username":"alice"}, "committer": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"alice@a.com","avatar_url":"","username":"alice"}, "timestamp": ""}
          ],
          "head_commit": null,
          "pusher": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""},
          "total_commits": 2
        }
        """.trimIndent()

        val issuesJson = """
        {
          "action": "opened",
          "issue": {
            "id": 100, "number": 42, "title": "Bug report",
            "body": "Something is broken", "state": "open",
            "html_url": "https://gitea.example.com/user/repo/issues/42",
            "user": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
            "is_pull": false, "comments": 0, "created_at": "", "updated_at": ""
          },
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}
        }
        """.trimIndent()

        val prJson = """
        {
          "action": "opened", "number": 7,
          "pull_request": {
            "id": 200, "number": 7, "title": "Add feature X",
            "body": "This PR adds feature X", "state": "open", "merged": false,
            "html_url": "https://gitea.example.com/user/repo/pulls/7",
            "user": {"id":3,"login":"charlie","login_name":"charlie","full_name":"Charlie","email":"","avatar_url":"","username":"charlie"},
            "head": {"label":"feature","ref":"feature","sha":"sha123","repo":{"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}},
            "base": {"label":"master","ref":"master","sha":"sha456","repo":{"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}},
            "created_at": "", "updated_at": ""
          },
          "sender": {"id":3,"login":"charlie","login_name":"charlie","full_name":"Charlie","email":"","avatar_url":"","username":"charlie"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}
        }
        """.trimIndent()

        val createJson = """
        {
          "ref": "feature-x", "ref_type": "branch",
          "sha": "abc123def456",
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}
        }
        """.trimIndent()

        val deleteJson = """
        {
          "ref": "old-branch", "ref_type": "branch",
          "sha": "abc123",
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}
        }
        """.trimIndent()

        val releaseJson = """
        {
          "action": "published",
          "release": {
            "id": 1, "tag_name": "v1.0.0", "target_commitish": "master",
            "name": "First Release", "body": "Initial release",
            "draft": false, "prerelease": false,
            "url": "", "html_url": "https://gitea.example.com/user/repo/releases/tag/v1.0.0",
            "author": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
            "created_at": ""
          },
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"Alice","email":"","avatar_url":"","username":"alice"},
          "repository": {"id":1,"name":"repo","full_name":"user/repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"master","private":false,"website":""}
        }
        """.trimIndent()

        val repoJson = """
        {
          "action": "created",
          "repository": {"id":5,"name":"new-repo","full_name":"user/new-repo","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"main","private":false,"website":""},
          "sender": {"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"}
        }
        """.trimIndent()

        val forkJson = """
        {
          "forkee": {"id":6,"name":"original","full_name":"alice/original","owner":{"id":2,"login":"alice","login_name":"alice","full_name":"","email":"","avatar_url":"","username":"alice"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"main","private":false,"website":""},
          "repository": {"id":1,"name":"original","full_name":"user/original","owner":{"id":1,"login":"user","login_name":"user","full_name":"","email":"","avatar_url":"","username":"user"},"html_url":"","description":"","ssh_url":"","clone_url":"","default_branch":"main","private":false,"website":""},
          "sender": {"id":2,"login":"alice","login_name":"alice","full_name":"","email":"","avatar_url":"","username":"alice"}
        }
        """.trimIndent()
    }
}
