import { AuthRequestError } from '@/services/authSession'

export interface AdminUser {
  id: string
  userName: string
  roles: string[]
  isActive: boolean
  mustChangePassword: boolean
}

interface ApiMessageResponse {
  message?: unknown
}

function isObject(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null
}

function normalizeAdminUser(value: unknown): AdminUser | null {
  if (!isObject(value)) {
    return null
  }

  const { id, userName, roles, isActive, mustChangePassword } = value
  if (typeof id !== 'string') {
    return null
  }

  const normalizedRoles = Array.isArray(roles)
    ? roles
        .filter((entry): entry is string => typeof entry === 'string')
        .map((entry) => entry.trim())
        .filter((entry) => entry.length > 0)
    : []

  return {
    id,
    userName: typeof userName === 'string' ? userName : '',
    roles: normalizedRoles,
    isActive: Boolean(isActive),
    mustChangePassword: Boolean(mustChangePassword),
  }
}

async function readApiMessage(response: Response): Promise<string | null> {
  const contentType = response.headers.get('content-type') ?? ''
  if (!contentType.toLowerCase().includes('application/json')) {
    return null
  }

  try {
    const payload = (await response.json()) as ApiMessageResponse
    if (typeof payload.message === 'string' && payload.message.trim().length > 0) {
      return payload.message.trim()
    }
  } catch {
    return null
  }

  return null
}

function toAdminUserError(error: unknown, fallbackMessage: string): AuthRequestError {
  if (error instanceof AuthRequestError) {
    return error
  }

  return new AuthRequestError(fallbackMessage, 0)
}

export async function fetchAdminUsers(): Promise<AdminUser[]> {
  let response: Response

  try {
    response = await fetch('/auth/user', {
      method: 'GET',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
      },
    })
  } catch (error) {
    throw toAdminUserError(error, 'Server ist nicht erreichbar. Bitte später erneut versuchen.')
  }

  if (response.status === 401) {
    throw new AuthRequestError('Session abgelaufen. Bitte melde dich erneut an.', response.status)
  }

  if (response.status === 403) {
    throw new AuthRequestError('Du bist angemeldet, aber nicht als Admin autorisiert.', response.status)
  }

  if (!response.ok) {
    const apiMessage = await readApiMessage(response)
    throw new AuthRequestError(
      apiMessage ?? 'Benutzerliste konnte nicht geladen werden.',
      response.status,
    )
  }

  const payload: unknown = await response.json()
  if (!Array.isArray(payload)) {
    throw new AuthRequestError('Antwortformat von /auth/user ist ungültig.', response.status)
  }

  const users = payload.map(normalizeAdminUser)
  if (users.some((user) => user === null)) {
    throw new AuthRequestError('Antwortformat von /auth/user ist ungültig.', response.status)
  }

  return users as AdminUser[]
}

export async function fetchAdminUserById(userId: string): Promise<AdminUser> {
  const normalizedId = userId.trim()
  if (normalizedId.length === 0) {
    throw new AuthRequestError('Ungültige Benutzer-ID.', 400)
  }

  let response: Response

  try {
    response = await fetch(`/auth/user/${encodeURIComponent(normalizedId)}`, {
      method: 'GET',
      credentials: 'include',
      headers: {
        Accept: 'application/json',
      },
    })
  } catch (error) {
    throw toAdminUserError(error, 'Server ist nicht erreichbar. Bitte später erneut versuchen.')
  }

  if (response.status === 401) {
    throw new AuthRequestError('Session abgelaufen. Bitte melde dich erneut an.', response.status)
  }

  if (response.status === 403) {
    throw new AuthRequestError('Du bist angemeldet, aber nicht als Admin autorisiert.', response.status)
  }

  if (response.status === 404) {
    throw new AuthRequestError('Benutzer wurde nicht gefunden.', response.status)
  }

  if (!response.ok) {
    const apiMessage = await readApiMessage(response)
    throw new AuthRequestError(
      apiMessage ?? 'Benutzerdetails konnten nicht geladen werden.',
      response.status,
    )
  }

  const payload: unknown = await response.json()
  const user = normalizeAdminUser(payload)
  if (!user) {
    throw new AuthRequestError('Antwortformat von /auth/user/{id} ist ungültig.', response.status)
  }

  return user
}
