import { describe, it, expect, vi, beforeEach } from "vitest"
import { prisma } from "@codeflash-ai/common"
import { getActionAccountContext } from "@/lib/server/get-account-context"

vi.mock("@/lib/server-action-timing", () => ({
  withTiming: vi.fn((_name: string, fn: Function) => fn),
}))

vi.mock("@/lib/analytics/tracking", () => ({
  trackMemberInvited: vi.fn(),
}))

vi.mock("@/lib/server/get-account-context", () => ({
  getActionAccountContext: vi.fn(),
}))

const mockOrg = {
  id: "org-1",
  organization_members: [
    {
      id: "member-1",
      user_id: "user-1",
      role: "admin",
      added_at: new Date("2024-01-15"),
      user: {
        github_username: "alice",
        name: "Alice Smith",
        email: "alice@example.com",
      },
    },
    {
      id: "member-2",
      user_id: "user-2",
      role: "member",
      added_at: new Date("2024-02-01"),
      user: {
        github_username: "bob",
        name: "Bob Jones",
        email: "bob@example.com",
      },
    },
  ],
}

describe("getOrganizationMembers", () => {
  let getOrganizationMembers: typeof import("../action").getOrganizationMembers

  beforeEach(async () => {
    vi.clearAllMocks()
    vi.mocked(getActionAccountContext).mockResolvedValue({
      payload: { userId: "user-1", username: "testuser" },
      userId: "user-1",
      username: "testuser",
    })

    const mod = await import("../action")
    getOrganizationMembers = mod.getOrganizationMembers
  })

  describe("successful retrieval", () => {
    it("returns members when user has access", async () => {
      vi.mocked(prisma.organizations.findUnique).mockResolvedValue(mockOrg as any)
      vi.mocked(prisma.organization_members.findUnique).mockResolvedValue({ id: "member-1" } as any)

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(true)
      expect(result.data).toHaveLength(2)
    })

    it("maps nested organization_members to flat Member structure", async () => {
      vi.mocked(prisma.organizations.findUnique).mockResolvedValue(mockOrg as any)
      vi.mocked(prisma.organization_members.findUnique).mockResolvedValue({ id: "member-1" } as any)

      const result = await getOrganizationMembers("org-1")
      const member = result.data![0]

      expect(member).toEqual({
        id: "member-1",
        user_id: "user-1",
        username: "alice",
        name: "Alice Smith",
        email: "alice@example.com",
        role: "admin",
        added_at: new Date("2024-01-15"),
        avatarUrl: "https://github.com/alice.png",
      })
    })
  })

  describe("access control", () => {
    it("returns error when organization not found", async () => {
      vi.mocked(prisma.organizations.findUnique).mockResolvedValue(null)
      vi.mocked(prisma.organization_members.findUnique).mockResolvedValue(null)

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(false)
      expect(result.error).toBe("Organization not found")
    })

    it("returns unauthorized when there is no active session", async () => {
      vi.mocked(getActionAccountContext).mockResolvedValue(null)

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(false)
      expect(result.error).toBe("Unauthorized")
      expect(prisma.organizations.findUnique).not.toHaveBeenCalled()
    })

    it("returns error when user is not in organization members", async () => {
      vi.mocked(getActionAccountContext).mockResolvedValue({
        payload: { userId: "unknown-user", username: "testuser" },
        userId: "unknown-user",
        username: "testuser",
      })
      vi.mocked(prisma.organizations.findUnique).mockResolvedValue(mockOrg as any)
      vi.mocked(prisma.organization_members.findUnique).mockResolvedValue(null)

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(false)
      expect(result.error).toBe("You don't have access to this organization")
    })
  })

  describe("error handling", () => {
    it("returns error response when Prisma throws", async () => {
      vi.mocked(prisma.organizations.findUnique).mockRejectedValue(new Error("Connection failed"))

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(false)
      expect(result.error).toBe("Connection failed")
    })

    it("uses fallback message for non-Error exceptions", async () => {
      vi.mocked(prisma.organizations.findUnique).mockRejectedValue("string error")

      const result = await getOrganizationMembers("org-1")

      expect(result.success).toBe(false)
      expect(result.error).toBe("Failed to get members")
    })
  })
})
