import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { MessageProvider } from '@insignia/iios-message-web';
import { RestClient, type Ticket, type CallbackRequest, type TicketState } from '@insignia/iios-kernel-client';

const SupportContext = createContext<RestClient | null>(null);

/** Wraps MessageProvider (chat) and provides a support REST client. */
export function SupportProvider({
  serviceUrl,
  token,
  children,
}: {
  serviceUrl: string;
  token: string;
  children: React.ReactNode;
}): React.ReactElement {
  const client = useMemo(() => new RestClient({ serviceUrl, token }), [serviceUrl, token]);
  return (
    <SupportContext.Provider value={client}>
      <MessageProvider serviceUrl={serviceUrl} token={token}>
        {children}
      </MessageProvider>
    </SupportContext.Provider>
  );
}

function useSupportClient(): RestClient {
  const c = useContext(SupportContext);
  if (!c) throw new Error('support hooks must be used within <SupportProvider>');
  return c;
}

/** Escalate a chat thread to support (creates + queues a ticket). */
export function useEscalate(): (threadId: string, subject?: string) => Promise<Ticket> {
  const client = useSupportClient();
  return (threadId, subject) => client.escalate(threadId, subject);
}

/** The caller's tickets (scope 'mine') or an agent's assigned tickets ('assigned'). */
export function useTickets(scope: 'mine' | 'assigned' = 'mine', pollMs = 3000): {
  tickets: Ticket[];
  refresh: () => Promise<void>;
  createTicket: (subject: string, opts?: { priority?: string; threadId?: string }) => Promise<Ticket>;
  patch: (id: string, state: TicketState) => Promise<void>;
} {
  const client = useSupportClient();
  const [tickets, setTickets] = useState<Ticket[]>([]);
  const refresh = useCallback(async () => {
    try {
      setTickets(await client.listTickets(scope));
    } catch {
      /* transient */
    }
  }, [client, scope]);
  useEffect(() => {
    void refresh();
    const t = setInterval(() => void refresh(), pollMs);
    return () => clearInterval(t);
  }, [refresh, pollMs]);
  const createTicket = async (subject: string, opts?: { priority?: string; threadId?: string }) => {
    const t = await client.createTicket({ subject, ...opts });
    await refresh();
    return t;
  };
  const patch = async (id: string, state: TicketState) => {
    await client.patchTicket(id, state);
    await refresh();
  };
  return { tickets, refresh, createTicket, patch };
}

/** Agent convenience: their assigned tickets. */
export function useAssignedTickets(pollMs = 3000) {
  return useTickets('assigned', pollMs);
}

export function useCallbackRequest(): (input: {
  preferChannel: string;
  preferredTime?: string;
  notes?: string;
  ticketId?: string;
}) => Promise<CallbackRequest> {
  const client = useSupportClient();
  return (input) => client.requestCallback(input);
}

/** Agent presence: set AVAILABLE/OFFLINE. */
export function useAvailability(): (state: string) => Promise<unknown> {
  const client = useSupportClient();
  return (state) => client.setAvailability(state);
}

/** Agent onboarding: join the default queue + go AVAILABLE (self-seed). */
export function useGoOnline(): () => Promise<void> {
  const client = useSupportClient();
  return async () => {
    await client.joinDefaultQueue();
    await client.setAvailability('AVAILABLE');
  };
}
