import { createContext, createSignal, useContext, onMount, Accessor, JSX } from 'solid-js';
import { getClerk, loadClerk, getClerkUrls } from './clerk-client';
import { User, UserRole, AuthState } from './types';

type ClerkUser = any;

interface ClerkSession {
  getId: () => string;
  getUser: () => ClerkUser;
}

interface ClerkClient {
  user: () => ClerkUser | null;
  session: () => ClerkSession | null;
  isLoading: boolean;
  signOut: () => Promise<void>;
}

const AuthContext = createContext<Accessor<AuthState> | undefined>(undefined);
const AuthActionsContext = createContext<{
  signIn: () => void;
  signOut: () => Promise<void>;
  updateUser: (data: Partial<User>) => Promise<void>;
  clerkClient: Accessor<ClerkClient | null>;
} | undefined>(undefined);

export { AuthContext, AuthActionsContext };

function clerkUserToUser(clerkUser: ClerkUser): User {
  const primaryEmail = clerkUser.primaryEmailAddress?.emailAddress || '';
  const firstName = clerkUser.firstName || '';
  const lastName = clerkUser.lastName || '';
  const name = [firstName, lastName].filter(Boolean).join(' ') || primaryEmail.split('@')[0] || 'User';

  return {
    id: clerkUser.id,
    email: primaryEmail,
    name,
    avatarUrl: clerkUser.imageUrl,
    role: 'owner' as UserRole,
  };
}

export function ClerkProvider(props: { children: JSX.Element }) {
  const [state, setState] = createSignal<AuthState>({
    user: null,
    isLoading: true,
    isAuthenticated: false,
    error: null,
  });

  const [clerkClient, setClerkClient] = createSignal<ClerkClient | null>(null);

  onMount(async () => {
    try {
      const client = await loadClerk();
      if (!client) {
        setState({
          user: null,
          isLoading: false,
          isAuthenticated: false,
          error: 'Authentication service unavailable',
        });
        return;
      }

      const wrappedClient: ClerkClient = {
        user: () => client.user,
        session: () => (client.session as any) || null,
        isLoading: false,
        signOut: async () => {
          await client.signOut();
          setState({
            user: null,
            isLoading: false,
            isAuthenticated: false,
            error: null,
          });
        },
      };

      setClerkClient(wrappedClient);

      if (client.user) {
        setState({
          user: clerkUserToUser(client.user),
          isLoading: false,
          isAuthenticated: true,
          error: null,
        });
      } else {
        setState((prev) => ({ ...prev, isLoading: false }));
      }
    } catch (err) {
      setState({
        user: null,
        isLoading: false,
        isAuthenticated: false,
        error: err instanceof Error ? err.message : 'Failed to initialize auth',
      });
    }
  });

  const signIn = () => {
    const urls = getClerkUrls();
    window.location.href = urls.signInUrl;
  };

  const signOut = async () => {
    const client = getClerk();
    if (client) {
      await client.signOut();
    }
    setState({
      user: null,
      isLoading: false,
      isAuthenticated: false,
      error: null,
    });
  };

  const updateUser = async (data: Partial<User>) => {
    setState((prev) => ({
      ...prev,
      user: prev.user ? { ...prev.user, ...data } : null,
    }));
  };

  return (
    <AuthContext.Provider value={state}>
      <AuthActionsContext.Provider value={{ signIn, signOut, updateUser, clerkClient }}>
        {props.children}
      </AuthActionsContext.Provider>
    </AuthContext.Provider>
  );
}

export function useAuth(): Accessor<AuthState> {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within a ClerkProvider');
  }
  return context;
}

export function useAuthActions() {
  const context = useContext(AuthActionsContext);
  if (!context) {
    throw new Error('useAuthActions must be used within a ClerkProvider');
  }
  return context;
}

export function requireAuth() {
  const auth = useAuth();
  const authState = auth();
  if (!authState.isAuthenticated) {
    throw new Error('Authentication required');
  }
  return authState.user!;
}
