import React from 'react';

import '@testing-library/jest-dom/vitest';

import { cleanup } from '@testing-library/react';
import { afterEach, vi } from 'vitest';

Object.defineProperty(globalThis, '__DEV__', {
  configurable: true,
  value: false,
});

const createElement =
  (tag: string) =>
  ({
    children,
    onChangeText,
    onPress,
    value,
    ...props
  }: {
    children?: React.ReactNode;
    onChangeText?: (value: string) => void;
    onPress?: () => void;
    value?: string;
    [key: string]: unknown;
  }) => {
    const safeProps: Record<string, unknown> = {
      ...props,
      className:
        typeof props.className === 'string' ? props.className : undefined,
      disabled: props.disabled as boolean | undefined,
      onChange: onChangeText
        ? (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
            onChangeText(event.currentTarget.value)
        : undefined,
      onClick: onPress,
      value,
    };
    delete safeProps.keyboardType;
    delete safeProps.keyboardShouldPersistTaps;
    delete safeProps.placeholderTextColor;
    delete safeProps.secureTextEntry;
    delete safeProps.showsHorizontalScrollIndicator;
    delete safeProps.textAlignVertical;

    return React.createElement(tag, safeProps, children);
  };

const TextInput = ({
  multiline,
  ...props
}: {
  multiline?: boolean;
  [key: string]: unknown;
}) => createElement(multiline ? 'textarea' : 'input')(props);

const mocks = vi.hoisted(() => ({
  alert: vi.fn(),
  useAction: vi.fn(() => vi.fn()),
  useMutation: vi.fn(() => vi.fn()),
  useQuery: vi.fn(() => undefined),
}));

vi.mock('react-native', () => ({
  Alert: { alert: mocks.alert },
  Linking: { openURL: vi.fn() },
  Modal: ({
    children,
    visible,
  }: {
    children?: React.ReactNode;
    visible?: boolean;
  }) => (visible ? React.createElement('div', {}, children) : null),
  Pressable: createElement('button'),
  Platform: {
    OS: 'web',
    select: (values: Record<string, unknown>) => values.web ?? values.default,
  },
  RefreshControl: createElement('div'),
  ScrollView: createElement('div'),
  Switch: createElement('input'),
  Text: createElement('span'),
  TextInput,
  TurboModuleRegistry: {
    get: vi.fn(() => undefined),
    getEnforcing: vi.fn(() => ({})),
  },
  View: createElement('div'),
}));

vi.mock('expo-clipboard', () => ({
  setStringAsync: vi.fn(),
}));

vi.mock('expo-haptics', () => ({
  impactAsync: vi.fn(),
  notificationAsync: vi.fn(),
  selectionAsync: vi.fn(),
}));

vi.mock('react-native-safe-area-context', () => ({
  SafeAreaView: createElement('div'),
}));

vi.mock('expo-router', () => ({
  Link: ({ children }: { children?: React.ReactNode }) => children,
  Stack: {
    Screen: () => null,
  },
  useLocalSearchParams: () => ({}),
  useRouter: () => ({
    push: vi.fn(),
    replace: vi.fn(),
  }),
}));

vi.mock('convex/react', () => ({
  useAction: mocks.useAction,
  useMutation: mocks.useMutation,
  useQuery: mocks.useQuery,
}));

vi.mock('@convex-dev/auth/react', () => ({
  useAuthActions: () => ({
    signIn: vi.fn(),
    signOut: vi.fn(),
  }),
}));

export const mockedAlert = mocks.alert;
export const mockedUseAction = mocks.useAction;
export const mockedUseMutation = mocks.useMutation;
export const mockedUseQuery = mocks.useQuery;

afterEach(() => {
  cleanup();
});
