import { useState, useCallback } from 'react';
import type { UserDTO, CreateUserRequest } from '@effigenix/api-client';
import { client } from '../utils/api-client.js';

type RoleName = CreateUserRequest['roleNames'][number];

interface UsersState {
  users: UserDTO[];
  loading: boolean;
  error: string | null;
}

function errorMessage(err: unknown): string {
  return err instanceof Error ? err.message : 'Unbekannter Fehler';
}

export function useUsers() {
  const [state, setState] = useState<UsersState>({
    users: [],
    loading: false,
    error: null,
  });

  const fetchUsers = useCallback(async () => {
    setState((s) => ({ ...s, loading: true, error: null }));
    try {
      const users = await client.users.list();
      setState({ users, loading: false, error: null });
    } catch (err) {
      setState((s) => ({ ...s, loading: false, error: errorMessage(err) }));
    }
  }, []);

  const createUser = useCallback(
    async (username: string, email: string, password: string, roleName?: string) => {
      setState((s) => ({ ...s, loading: true, error: null }));
      try {
        const user = await client.users.create({
          username,
          email,
          password,
          roleNames: roleName ? [roleName as RoleName] : [],
        });
        setState((s) => ({ users: [...s.users, user], loading: false, error: null }));
        return user;
      } catch (err) {
        setState((s) => ({ ...s, loading: false, error: errorMessage(err) }));
        return null;
      }
    },
    [],
  );

  const lockUser = useCallback(async (id: string) => {
    try {
      const user = await client.users.lock(id);
      setState((s) => ({
        ...s,
        users: s.users.map((u) => (u.id === id ? user : u)),
      }));
      return user;
    } catch (err) {
      setState((s) => ({ ...s, error: errorMessage(err) }));
      return null;
    }
  }, []);

  const unlockUser = useCallback(async (id: string) => {
    try {
      const user = await client.users.unlock(id);
      setState((s) => ({
        ...s,
        users: s.users.map((u) => (u.id === id ? user : u)),
      }));
      return user;
    } catch (err) {
      setState((s) => ({ ...s, error: errorMessage(err) }));
      return null;
    }
  }, []);

  const assignRole = useCallback(async (id: string, roleName: string) => {
    try {
      const user = await client.users.assignRole(id, { roleName: roleName as RoleName });
      setState((s) => ({
        ...s,
        users: s.users.map((u) => (u.id === id ? user : u)),
      }));
      return user;
    } catch (err) {
      setState((s) => ({ ...s, error: errorMessage(err) }));
      return null;
    }
  }, []);

  const removeRole = useCallback(async (id: string, roleName: string) => {
    try {
      await client.users.removeRole(id, roleName);
      const updated = await client.users.getById(id);
      setState((s) => ({
        ...s,
        users: s.users.map((u) => (u.id === id ? updated : u)),
      }));
      return true;
    } catch (err) {
      setState((s) => ({ ...s, error: errorMessage(err) }));
      return false;
    }
  }, []);

  const changePassword = useCallback(
    async (id: string, currentPassword: string, newPassword: string) => {
      try {
        await client.users.changePassword(id, { currentPassword, newPassword });
        return true;
      } catch (err) {
        setState((s) => ({ ...s, error: errorMessage(err) }));
        return false;
      }
    },
    [],
  );

  const clearError = useCallback(() => {
    setState((s) => ({ ...s, error: null }));
  }, []);

  return {
    ...state,
    fetchUsers,
    createUser,
    lockUser,
    unlockUser,
    assignRole,
    removeRole,
    changePassword,
    clearError,
  };
}
