'use client'

import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { fetchJson } from '@/hooks/selectors/helpers'

export interface CredentialSet {
  id: string
  name: string
  description: string | null
  providerId: string | null
  createdBy: string
  createdAt: string
  updatedAt: string
  creatorName: string | null
  creatorEmail: string | null
  memberCount: number
}

export interface CredentialSetMembership {
  membershipId: string
  status: string
  joinedAt: string | null
  credentialSetId: string
  credentialSetName: string
  credentialSetDescription: string | null
  providerId: string | null
  organizationId: string
  organizationName: string
}

export interface CredentialSetInvitation {
  invitationId: string
  token: string
  status: string
  expiresAt: string
  createdAt: string
  credentialSetId: string
  credentialSetName: string
  providerId: string | null
  organizationId: string
  organizationName: string
  invitedByName: string | null
  invitedByEmail: string | null
}

interface CredentialSetsResponse {
  credentialSets?: CredentialSet[]
}

interface MembershipsResponse {
  memberships?: CredentialSetMembership[]
}

interface InvitationsResponse {
  invitations?: CredentialSetInvitation[]
}

export const credentialSetKeys = {
  all: ['credentialSets'] as const,
  lists: () => [...credentialSetKeys.all, 'list'] as const,
  list: (organizationId?: string) =>
    [...credentialSetKeys.lists(), organizationId ?? 'none'] as const,
  details: () => [...credentialSetKeys.all, 'detail'] as const,
  detail: (id?: string) => [...credentialSetKeys.details(), id ?? 'none'] as const,
  detailMembers: (credentialSetId?: string) =>
    [...credentialSetKeys.detail(credentialSetId), 'members'] as const,
  detailInvitations: (credentialSetId?: string) =>
    [...credentialSetKeys.detail(credentialSetId), 'invitations'] as const,
  memberships: () => [...credentialSetKeys.all, 'memberships'] as const,
  invitations: () => [...credentialSetKeys.all, 'invitations'] as const,
}

export async function fetchCredentialSets(
  organizationId: string,
  signal?: AbortSignal
): Promise<CredentialSet[]> {
  if (!organizationId) return []
  const data = await fetchJson<CredentialSetsResponse>('/api/credential-sets', {
    searchParams: { organizationId },
    signal,
  })
  return data.credentialSets ?? []
}

export function useCredentialSets(organizationId?: string, enabled = true) {
  return useQuery<CredentialSet[]>({
    queryKey: credentialSetKeys.list(organizationId),
    queryFn: ({ signal }) => fetchCredentialSets(organizationId ?? '', signal),
    enabled: Boolean(organizationId) && enabled,
    staleTime: 60 * 1000,
    placeholderData: keepPreviousData,
  })
}

interface CredentialSetDetailResponse {
  credentialSet?: CredentialSet
}

export async function fetchCredentialSetById(
  id: string,
  signal?: AbortSignal
): Promise<CredentialSet | null> {
  if (!id) return null
  const data = await fetchJson<CredentialSetDetailResponse>(`/api/credential-sets/${id}`, {
    signal,
  })
  return data.credentialSet ?? null
}

export function useCredentialSetDetail(id?: string, enabled = true) {
  return useQuery<CredentialSet | null>({
    queryKey: credentialSetKeys.detail(id),
    queryFn: ({ signal }) => fetchCredentialSetById(id ?? '', signal),
    enabled: Boolean(id) && enabled,
    staleTime: 60 * 1000,
    placeholderData: keepPreviousData,
  })
}

export function useCredentialSetMemberships() {
  return useQuery<CredentialSetMembership[]>({
    queryKey: credentialSetKeys.memberships(),
    queryFn: async ({ signal }) => {
      const data = await fetchJson<MembershipsResponse>('/api/credential-sets/memberships', {
        signal,
      })
      return data.memberships ?? []
    },
    staleTime: 60 * 1000,
  })
}

export function useCredentialSetInvitations() {
  return useQuery<CredentialSetInvitation[]>({
    queryKey: credentialSetKeys.invitations(),
    queryFn: async ({ signal }) => {
      const data = await fetchJson<InvitationsResponse>('/api/credential-sets/invitations', {
        signal,
      })
      return data.invitations ?? []
    },
    staleTime: 30 * 1000,
  })
}

export function useAcceptCredentialSetInvitation() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (token: string) => {
      const response = await fetch(`/api/credential-sets/invite/${token}`, {
        method: 'POST',
      })
      if (!response.ok) {
        const data = await response.json()
        throw new Error(data.error || 'Failed to accept invitation')
      }
      return response.json()
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() })
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.invitations() })
    },
  })
}

export interface CreateCredentialSetData {
  organizationId: string
  name: string
  description?: string
  providerId?: string
}

export function useCreateCredentialSet() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (data: CreateCredentialSetData) => {
      const response = await fetch('/api/credential-sets', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      })
      if (!response.ok) {
        const result = await response.json()
        throw new Error(result.error || 'Failed to create credential set')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.list(variables.organizationId) })
    },
  })
}

export function useCreateCredentialSetInvitation() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (data: { credentialSetId: string; email?: string }) => {
      const response = await fetch(`/api/credential-sets/${data.credentialSetId}/invite`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: data.email }),
      })
      if (!response.ok) {
        const result = await response.json()
        throw new Error(result.error || 'Failed to create invitation')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.detailInvitations(variables.credentialSetId),
      })
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.invitations() })
    },
  })
}

export interface CredentialSetMember {
  id: string
  userId: string
  status: string
  joinedAt: string | null
  createdAt: string
  userName: string | null
  userEmail: string | null
  userImage: string | null
  credentials: { providerId: string; accountId: string }[]
}

interface MembersResponse {
  members?: CredentialSetMember[]
}

export function useCredentialSetMembers(credentialSetId?: string) {
  return useQuery<CredentialSetMember[]>({
    queryKey: credentialSetKeys.detailMembers(credentialSetId),
    queryFn: async ({ signal }) => {
      const data = await fetchJson<MembersResponse>(
        `/api/credential-sets/${credentialSetId}/members`,
        { signal }
      )
      return data.members ?? []
    },
    enabled: Boolean(credentialSetId),
    staleTime: 30 * 1000,
  })
}

export function useRemoveCredentialSetMember() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (data: { credentialSetId: string; memberId: string }) => {
      const response = await fetch(
        `/api/credential-sets/${data.credentialSetId}/members?memberId=${data.memberId}`,
        { method: 'DELETE' }
      )
      if (!response.ok) {
        const result = await response.json()
        throw new Error(result.error || 'Failed to remove member')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.detailMembers(variables.credentialSetId),
      })
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() })
    },
  })
}

export function useLeaveCredentialSet() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (credentialSetId: string) => {
      const response = await fetch(
        `/api/credential-sets/memberships?credentialSetId=${credentialSetId}`,
        { method: 'DELETE' }
      )
      if (!response.ok) {
        const data = await response.json()
        throw new Error(data.error || 'Failed to leave credential set')
      }
      return response.json()
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() })
    },
  })
}

export interface DeleteCredentialSetParams {
  credentialSetId: string
  organizationId: string
}

export function useDeleteCredentialSet() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async ({ credentialSetId }: DeleteCredentialSetParams) => {
      const response = await fetch(`/api/credential-sets/${credentialSetId}`, {
        method: 'DELETE',
      })
      if (!response.ok) {
        const data = await response.json()
        throw new Error(data.error || 'Failed to delete credential set')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.list(variables.organizationId),
      })
      queryClient.invalidateQueries({ queryKey: credentialSetKeys.memberships() })
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.detail(variables.credentialSetId),
      })
    },
  })
}

export interface CredentialSetInvitationDetail {
  id: string
  credentialSetId: string
  email: string | null
  token: string
  status: string
  expiresAt: string
  createdAt: string
  invitedBy: string
}

interface InvitationsDetailResponse {
  invitations?: CredentialSetInvitationDetail[]
}

export function useCredentialSetInvitationsDetail(credentialSetId?: string) {
  return useQuery<CredentialSetInvitationDetail[]>({
    queryKey: credentialSetKeys.detailInvitations(credentialSetId),
    queryFn: async ({ signal }) => {
      const data = await fetchJson<InvitationsDetailResponse>(
        `/api/credential-sets/${credentialSetId}/invite`,
        { signal }
      )
      return (data.invitations ?? []).filter((inv) => inv.status === 'pending')
    },
    enabled: Boolean(credentialSetId),
    staleTime: 30 * 1000,
  })
}

export function useCancelCredentialSetInvitation() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (data: { credentialSetId: string; invitationId: string }) => {
      const response = await fetch(
        `/api/credential-sets/${data.credentialSetId}/invite?invitationId=${data.invitationId}`,
        { method: 'DELETE' }
      )
      if (!response.ok) {
        const result = await response.json()
        throw new Error(result.error || 'Failed to cancel invitation')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.detailInvitations(variables.credentialSetId),
      })
    },
  })
}

export function useResendCredentialSetInvitation() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: async (data: { credentialSetId: string; invitationId: string; email: string }) => {
      const response = await fetch(
        `/api/credential-sets/${data.credentialSetId}/invite/${data.invitationId}`,
        { method: 'POST' }
      )
      if (!response.ok) {
        const result = await response.json()
        throw new Error(result.error || 'Failed to resend invitation')
      }
      return response.json()
    },
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: credentialSetKeys.detailInvitations(variables.credentialSetId),
      })
    },
  })
}
