import { renderHook, waitFor } from "@testing-library/react"
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import React from "react"

import {
  useMembersQuery,
  useMemberQuery,
  useMemberQuotaQuery,
  useCreateMemberMutation,
  useUpdateMemberMutation,
} from "@/services/members"

import { server } from "../mocks/server"
import { mockMembersPage, mockQuotaStatus } from "../mocks/handlers"

beforeAll(() => server.listen({ onUnhandledRequest: "error" }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

function createWrapper() {
  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false, gcTime: 0 } },
  })
  return function Wrapper({ children }: { children: React.ReactNode }) {
    return (
      <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
    )
  }
}

describe("useMembersQuery", () => {
  it("returns paginated members data on success", async () => {
    const { result } = renderHook(() => useMembersQuery(), {
      wrapper: createWrapper(),
    })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(result.current.data).toEqual(mockMembersPage)
    expect(result.current.data?.content).toHaveLength(2)
    expect(result.current.data?.totalElements).toBe(2)
  })

  it("passes filter params to API", async () => {
    const { result } = renderHook(
      () => useMembersQuery({ page: 1, size: 10, search: "Max" }),
      { wrapper: createWrapper() }
    )

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data?.content).toHaveLength(2)
  })

  it("returns error state on API failure", async () => {
    const { http, HttpResponse } = await import("msw")
    server.use(
      http.get("/api/backend/members", () => {
        return HttpResponse.json(
          { code: "SERVER_ERROR", message: "Internal error" },
          { status: 500 }
        )
      })
    )

    const { result } = renderHook(() => useMembersQuery(), {
      wrapper: createWrapper(),
    })

    await waitFor(() => expect(result.current.isError).toBe(true))
    expect(result.current.error).toBeDefined()
  })
})

describe("useMemberQuery", () => {
  it("fetches single member by id", async () => {
    const { result } = renderHook(() => useMemberQuery("m1"), {
      wrapper: createWrapper(),
    })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data?.id).toBe("m1")
    expect(result.current.data?.firstName).toBe("Max")
  })
})

describe("useMemberQuotaQuery", () => {
  it("returns quota for given member", async () => {
    const { result } = renderHook(() => useMemberQuotaQuery("m1"), {
      wrapper: createWrapper(),
    })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data).toEqual(mockQuotaStatus)
    expect(result.current.data?.remainingGrams).toBe(35)
  })
})

describe("useCreateMemberMutation", () => {
  it("calls POST and returns new member", async () => {
    const { result } = renderHook(() => useCreateMemberMutation(), {
      wrapper: createWrapper(),
    })

    result.current.mutate({
      firstName: "New",
      lastName: "Member",
      email: "new@example.com",
      dateOfBirth: "2000-01-01",
    })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data?.firstName).toBe("New")
    expect(result.current.data?.status).toBe("ACTIVE")
  })
})

describe("useUpdateMemberMutation", () => {
  it("calls PUT and returns updated member", async () => {
    const { result } = renderHook(() => useUpdateMemberMutation("m1"), {
      wrapper: createWrapper(),
    })

    result.current.mutate({ firstName: "Updated" })

    await waitFor(() => expect(result.current.isSuccess).toBe(true))
    expect(result.current.data?.firstName).toBe("Updated")
  })
})
