import { Fn } from '@toktokhan-dev/universal';
import * as react from 'react';
import { CSSProperties, ComponentType, Component, ReactNode } from 'react';
import { AxiosRequestConfig, AxiosError } from 'axios';
import { Immutable } from 'immer';
import * as react_jsx_runtime from 'react/jsx-runtime';

/**
 * @category Hooks
 */
declare const useCallbackRef: <T extends Fn>(callback: T) => T;

interface TimerProps {
    /**
     * 타이머의 제한 시간(밀리초 단위)
     */
    timeLimit?: number;
    /**
     * 타이머가 초기화 시 자동으로 시작될지 여부
     * @default true
     */
    autoStart?: boolean;
    /**
     * 타이머가 업데이트되는 간격(밀리초 단위)
     * @default 1000ms
     */
    interval?: number;
    /**
     * 시간을 표시하는 형식을 설정하는 함수
     * @default ()=>"mm:ss" 형식
     */
    setTimeFormat?: (time: number) => string;
    /**
     * 시간이 종료되었을 때 호출되는 콜백 함수
     */
    onTimeOver?: () => void;
    /**
     * 매 시간 업데이트 시 호출되는 콜백 함수
     */
    onTimeUpdate?: (time: number) => void;
}
type TimerStatus = 'RUNNING' | 'PAUSED' | 'STOPPED';
/**
 * @category Hooks/useTimer()
 * 타이머를 관리하는 커스텀 훅입니다.
 *
 */
declare const useTimer: ({ autoStart, timeLimit, interval, setTimeFormat, onTimeOver, onTimeUpdate, }?: TimerProps) => {
    time: string;
    isEnd: boolean;
    start: () => void;
    restart: () => void;
    pause: () => void;
    reset: () => void;
};
/**
 * @category Hooks/useTimer()/Context(Optional)
 * 이 프로바이더는 타이머 상태를 컨텍스트를 통해 지역/전역적으로 관리할 수 있도록 해줍니다.
 *
 * @remarks 컨텍스트를 사용하지 않아도 타이머 훅을 직접 사용할 수 있으며, 컨텍스트가 필요한 경우에만 사용하시기 바랍니다.
 * 예를 들어, 다수의 컴포넌트에서 타이머 상태를 공유하거나, 전역적으로 타이머 상태를 관리해야 하는 경우에 유용합니다.
 *
 * @example
 * ```tsx
 * // TimerContainer.tsx
 * import React from 'react';
 * import { TimerProvider } from '@toktokhan-dev/react-universal';
 * import TimerDisplay from './TimerDisplay';
 *
 * const TimerContainer = () => {
 *   return (
 *     <TimerProvider
 *        params={{
 *          autoStart: false,
 *          timeLimit: 1000 * 5,
 *        }}
 *      >
 *       <TimerDisplay />
 *     </TimerProvider>
 *   );
 * };
 *
 * export default TimerContainer;
 *
 * // TimerDisplay.tsx
 * const TimerDisplay = () => {
 *   // 불필요한 리랜더링 방지를 위해 selector로 가져오시는 것을 권장합니다.
 *   const time = useTimerContext((ctx) => ctx?.time)
 *   const start = useTimerContext((ctx) => ctx?.start)
 *
 *   return (
 *     <div>
 *       <button onClick={start}>Start Timer</button>
 *       <p>Remaining Time: {time}</p>
 *     </div>
 *   );
 * };
 * ```
 */
declare const TimerProvider: ({ children, params, }: {
    children: react.ReactNode;
    params?: TimerProps | undefined;
}) => JSX.Element;
/**
 * @category Hooks/useTimer()/Context(Optional)
 * 타이머 컨텍스트를 사용하는 커스텀 훅입니다. selector를 통해 컨텍스트의 값을 가져올 수 있습니다.
 *
 * @remarks 컨텍스트를 사용하지 않아도 타이머 훅을 직접 사용할 수 있으며, 컨텍스트가 필요한 경우에만 사용하시기 바랍니다.
 * 예를 들어, 다수의 컴포넌트에서 타이머 상태를 공유하거나, 전역적으로 타이머 상태를 관리해야 하는 경우에 유용합니다.
 *
 * @example
 * ```tsx
 * import React from 'react';
 * import { useTimerContext } from '@toktokhan-dev/react-universal';
 *
 * const TimerDisplay = () => {
 *   // 불필요한 리랜더링 방지를 위해 selector로 가져오시는 것을 권장합니다.
 *   const time = useTimerContext((ctx) => ctx?.time)
 *   const start = useTimerContext((ctx) => ctx?.start)
 *
 *   return (
 *     <div>
 *       <button onClick={start}>Start Timer</button>
 *       <p>Remaining Time: {time}</p>
 *     </div>
 *   );
 * };
 *
 * export default TimerDisplay;
 * ```
 */
declare const useTimerContext: <Selected>(selector: (value: {
    time: string;
    isEnd: boolean;
    start: () => void;
    restart: () => void;
    pause: () => void;
    reset: () => void;
}) => Selected) => Selected;
/**
 * @category Hooks/useTimer()/Context(Optional)
 * 타이머 컨텍스트를 제공하는 컴포넌트 HOC입니다.
 * 이 HOC를 사용하여 컴포넌트를 래핑하면, 해당 컴포넌트와 하위 컴포넌트에서 타이머 상태를 공유할 수 있습니다.
 *
 * @remarks 컨텍스트를 사용하지 않아도 타이머 훅을 직접 사용할 수 있으며, 컨텍스트가 필요한 경우에만 사용하시기 바랍니다.
 * 예를 들어, 다수의 컴포넌트에서 타이머 상태를 공유하거나, 전역적으로 타이머 상태를 관리해야 하는 경우에 유용합니다.
 *
 * @example
 * ```tsx
 * // TimerContainer.tsx
 * import React from 'react';
 * import { withTimerProvider, useTimerContext } from '@toktokhan-dev/react-universal';
 *
 * const TimerContainer = () => {
 *   return <TimerDisplay />;
 * };
 *
 * export default withTimerProvider(TimerContainer, {
 *  autoStart: false,
 *  timeLimit: 1000 * 5,
 * });
 *
 * // TimerDisplay.tsx
 * const TimerDisplay = () => {
 *   // 불필요한 리랜더링 방지를 위해 selector로 가져오시는 것을 권장합니다.
 *   const time = useTimerContext((ctx) => ctx?.time)
 *   const start = useTimerContext((ctx) => ctx?.start)
 *
 *   return (
 *     <div>
 *       <button onClick={start}>Start Timer</button>
 *       <p>Remaining Time: {time}</p>
 *     </div>
 *   );
 * };
 * ```
 */
declare const withTimerProvider: <C extends react.ComponentType<any>>(Component: C, params?: TimerProps | undefined) => (props: PropsOf<C>) => JSX.Element;

/**
 * 특정 로직을 동작시킬 때 비동기로 제어권을 양도하는 로직을 쉽게 사용하기 위해 구현한 hooks 입니다.
 *
 * endYield 함수의 인자로 값을 전달한다면 startYield의 반환값으로 사용할 수 있습니다.
 *
 * @category Hooks
 *
 * @returns startYield / endYield 함수
 *
 * @example
 *
 * ```tsx
 *
 *  // hooks 선언
 *  const {endYield, startYield} = useYieldLogic();
 *
 *  // 변경함수
 *  const onClickSubmit = async() => {
 *  // 만약 유의사항을 띄워야 한다면 유의사항 모달을 띄운 후, startYield를 호출하여 함수의 제어권을 넘깁니다.
 *    if (isPrecaution) {
 *      openPrecautionModal();
 *      const count = await startYield();
 *    }
 *
 *    // 조회 API 호출로직...
 *  }

 *  const onClickPrecautionConfirm = () => {
 *   // 유의사항 모달에서 확인을 눌렀을 때 endYield를 호출하여 다시 제어권을 startYield 함수로 옮깁니다.
 *    endYield(3); // 인자의 유무는 자유이며, 여기서 전달한 인자를 startYield 에서 return받습니다.
 *    closePrecautionModal();
 *  }
 *
 *
 * ```
 *
 */
declare const useYieldLogic: <T>() => {
    startYield: () => Promise<unknown>;
    endYield: (v: T) => void;
};

/**
 * @param
 * @category Utils/File
 *
 * 개선
 */
declare const fileToBase64: (file: File) => Promise<string | ArrayBuffer | null>;

/**
 * @param
 * @category Utils/Format
 */
declare const formatNumberKR: (num: number) => string;

/**
 * @param
 * @category Utils/Format
 */
declare const formatPhoneNumberKR: (phone: string) => string;

type StyledConsoleArgs = {
    topic?: string;
    title?: string;
    data: unknown;
    topicColor?: CSSProperties['color'];
    method?: 'log' | 'warn' | 'error' | 'info';
    errors?: string;
};
/**
 * @param
 * @category Utils/Logger
 */
declare function styledConsole({ topic, title, data, topicColor, method, errors, }: StyledConsoleArgs): void;

interface ApiLoggerArgs extends Pick<StyledConsoleArgs, 'method'> {
    status: string | number;
    reqData?: AxiosRequestConfig;
    resData: any;
}
/**
 * @param
 * @category Utils/Logger
 */
declare const apiLogger: (params: ApiLoggerArgs) => void;

declare const defMessage = "\uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uACE0\uAC1D\uC13C\uD130\uC5D0 \uBB38\uC758\uD574\uC8FC\uC138\uC694.";
type ErrorMessage = {
    [key: string]: any;
};
type FormattedError = {
    name: string;
    message: string;
};
type GenErrorByServerType = {
    defMessage?: string;
    list?: FormattedError[];
    messagesWithKey?: string;
    messages?: string;
};
/**
 * 서버에서 발생한 오류를 기반으로 에러 메세지 객체를 반환합니다.
 * 외부 백엔드와 협업시에 에러타입을 확인해주세요.
 * api logger에서 사용하고 있으며, 에러 메세지를 통해 toast, alert 등에 적용시킬 수 있습니다.
 *
 * @category Utils/Logger
 * @template T - AxiosError 타입의 제네릭 매개변수입니다.
 * @param errors - AxiosError 객체입니다.
 * @returns 서버에서 발생한 오류에 기반한 에러메세지 객체입니다.
 */
declare const genErrorByServer: <T extends AxiosError<{
    message: ErrorMessage;
}, any>>(errors: T) => GenErrorByServerType;

/**
 * 주어진 컴포넌트의 props 타입을 추론하는 유틸리티 타입입니다.
 * @category Types/Utility
 *
 * @template T - props 타입을 추론할 컴포넌트.
 * @returns `T`가 `ComponentType` 또는 `Component`를 확장하는 경우 추론된 props 타입, 그렇지 않은 경우 `never`.
 *
 * @example
 * ```tsx
 * type Example = ComponentProps<(props: { number: number }) => JSX.Element>;
 * Example === { number : number }
 * ```
 */
type PropsOf<T> = T extends ComponentType<infer P> | Component<infer P> ? P : never;

type CreateContextSelectorReturn<T, P> = {
    useContext: <Selected>(selector: (value: T) => Selected) => Selected;
    Provider: ({ children, params, }: {
        children: ReactNode;
        params?: P;
    }) => JSX.Element;
    withProvider: <C extends ComponentType<any>>(Component: C, params?: P) => (props: PropsOf<C>) => JSX.Element;
};
/**
 * @category Utils/React
 * 커스텀 훅을 기반으로 컨텍스트와 관련된 유틸리티를 생성하는 함수입니다.
 * 이 함수는 주어진 훅을 컨텍스트로 감싸는 `Provider`, `useContext` 훅,
 * 그리고 컴포넌트를 컨텍스트로 감싸는 `withProvider` HOC를 반환합니다.
 *
 * @template T - 컨텍스트에서 사용할 데이터 타입
 * @template P - 훅의 파라미터 타입
 * @param useHook - 컨텍스트에서 사용할 커스텀 훅
 * @param initialProps - `useHook`에 전달될 초기 파라미터 (선택적)
 * @returns `{ useContext, Provider, withProvider }` - 생성된 컨텍스트 유틸리티들
 *
 * @example
 * ```tsx
 * // 커스텀 훅 정의
 * const useTimer = ({ timeLimit = 1000 }: { timeLimit?: number }) => {
 *   const [time, setTime] = useState(timeLimit);
 *   // 타이머 로직...
 *   return { time, start: () => { //타이머 시작 }};
 * };
 *
 * // createContextSelector로 컨텍스트 유틸리티 생성
 * const { Provider: TimerProvider, useContext: useTimerContext } = createContextSelector(useTimer);
 *
 * // 타이머를 표시하는 컴포넌트
 * const TimerDisplay = () => {
 *   const time = useTimerContext(ctx => ctx.time);
 *   return <div>Time: {time}</div>;
 * };
 *
 * // 방법 1. TimerProvider로 감싸기
 * const App = () => (
 *   <TimerProvider params={{timeLimit: 1000}}>
 *     <TimerDisplay />
 *   </TimerProvider>
 * );
 *
 * // 방법 2. withProvider로 컴포넌트 감싸기
 * const App = () => (
 *     <TimerDisplay />
 * );
 * export default withTimerProvider(App, { timeLimit: 1000 });
 * ```
 *
 */
declare const createContextSelector: <T, P = undefined>(useHook: (param?: P) => T, initialProps?: P) => CreateContextSelectorReturn<T, P>;

type ReducerMapFn<S, P> = (state: S, payload: P) => S | void;
type ReducerMap<S, P> = Record<string, ReducerMapFn<S, P>>;
type PayloadFrom<T> = T extends ReducerMapFn<any, infer P> ? P : never;
type ActionsByMap<S, R extends ReducerMap<S, any>> = {
    [key in keyof R]: undefined extends PayloadFrom<R[key]> ? {
        type: key;
        payload?: PayloadFrom<R[key]>;
    } : {
        type: key;
        payload: PayloadFrom<R[key]>;
    };
}[keyof R];

type CreateReducerParams<S, R extends ReducerMap<S, any>> = {
    initialState: S;
    reducers: R;
};
declare const NOTHING: unique symbol;
type ValidRecipeReturnType<State> = State | void | undefined | (State extends undefined ? typeof NOTHING : never);
/**
 * @param
 * @category Utils/React
 */
declare const createSlice: <S, R extends ReducerMap<S, any>>({ initialState, reducers, }: CreateReducerParams<S, R>) => {
    initialState: S;
    reducer: void | S extends ValidRecipeReturnType<S> ? (base: Immutable<S>, action: ActionsByMap<S, R>) => S : never;
};

interface EmptyViewProps {
    /**
     * 데이터가 존재할 때 렌더링될 UI 요소
     */
    children: ReactNode;
    /**
     * 데이터가 비어 있을 때 렌더링될 UI 요소
     */
    fallback: ReactNode;
    /**
     * 검사할 데이터 배열
     */
    data?: unknown[] | null;
}
/**
 * `EmptyView` 컴포넌트는 데이터가 비어있는 경우 `fallback`을,
 * 데이터가 존재하는 경우 `children`을 렌더링합니다.
 *
 * @category Components
 * @returns 조건에 따라 `children` 또는 `fallback`을 렌더링합니다.
 * @example
 * ```tsx
 * import EmptyView from './components/StateViews/EmptyView';
 *
 * const MyComponent = ({ data }) => (
 *   <EmptyView data={data} fallback={<div>데이터가 없습니다.</div>}>
 *     <div>데이터가 존재합니다.</div>
 *   </EmptyView>
 * );
 * ```
 */
declare const EmptyView: ({ children, data, fallback }: EmptyViewProps) => react_jsx_runtime.JSX.Element;

interface LoadingViewProps {
    /**
     * 로딩이 완료되었을 때 렌더링될 UI 요소
     */
    children: ReactNode;
    /**
     * 로딩 중일 때 렌더링될 UI 요소
     */
    fallback: ReactNode;
    /**
     * 로딩 상태를 나타내는 boolean 값
     */
    isLoading?: boolean;
}
/**
 * `LoadingView` 컴포넌트는 로딩 상태를 처리하여 로딩 중일 때는 `fallback`을,
 * 로딩이 완료되었을 때는 `children`을 렌더링합니다.
 *
 * @category Components
 * @returns 조건에 따라 `children` 또는 `fallback`을 렌더링합니다.
 * @example
 * ```tsx
 * import LoadingView from './components/StateViews/LoadingView';
 *
 * const MyComponent = ({ isLoading }) => (
 *   <LoadingView isLoading={isLoading} fallback={<div>로딩 중...</div>}>
 *     <div>로딩이 완료되었습니다.</div>
 *   </LoadingView>
 * );
 * ```
 */
declare const LoadingView: ({ children, isLoading, fallback, }: LoadingViewProps) => react_jsx_runtime.JSX.Element;

export { type ApiLoggerArgs, type CreateContextSelectorReturn, EmptyView, type EmptyViewProps, type ErrorMessage, type GenErrorByServerType, LoadingView, type LoadingViewProps, type PropsOf, type StyledConsoleArgs, type TimerProps, TimerProvider, type TimerStatus, apiLogger, createContextSelector, createSlice, defMessage, fileToBase64, formatNumberKR, formatPhoneNumberKR, genErrorByServer, styledConsole, useCallbackRef, useTimer, useTimerContext, useYieldLogic, withTimerProvider };
