import type { DomainAssociation } from '@api-client/core/modeling/DomainAssociation.js'
import type { DomainPropertyInputConfig } from '../types.js'
import type { IconType } from '../../md/icons/Icons.js'
import type { DomainProperty } from '@api-client/core/modeling/DomainProperty.js'
import {
  DomainAssociationKind,
  DomainEntityKind,
  DomainModelKind,
  DomainNamespaceKind,
  DomainPropertyKind,
} from '@api-client/core/models/kinds.js'
import type { DomainPropertyFormat } from '@api-client/core/modeling/DataFormat.js'

/**
 * Returns the icon to use for the given field (DomainProperty or DomainAssociation).
 * This is used to render the icon in the UI.
 *
 * @param p The field to get the icon for.
 * @returns The icon to use.
 */
export function getFieldIcon(p: DomainAssociation | DomainProperty): IconType {
  if (p.kind === DomainAssociationKind) {
    return 'link'
  }
  return getPropertyIcon(p as DomainProperty)
}

/**
 * Returns the label to use for the given field (DomainProperty or DomainAssociation).
 * @param p The field to get the label for.
 * @returns The label to use in the data type label.
 */
export function getFieldDataTypeLabel(p: DomainAssociation | DomainProperty): string {
  if (p.kind === DomainAssociationKind) {
    return 'Reference'
  }
  return getPropertyTypeLabel(p as DomainProperty)
}

/**
 * Generates an icon name for the DomainProperty that illustrate its primary purpose.
 */
export function getPropertyIcon(p: DomainProperty): IconType {
  if (p.primary) {
    return 'key'
  }
  switch (p.type) {
    // case 'integer':
    case 'number':
      return 'number'
    case 'date':
      return 'calendarToday'
    case 'time':
      return 'schedule'
    case 'datetime':
      return 'event'
    case 'boolean':
      return 'checkCircle'
    case 'binary':
      return 'draft'
    default:
      return 'textFields'
  }
}

/**
 * @returns The type label to use when rendering the DomainProperty in the UI
 */
export function getPropertyTypeLabel(p: DomainProperty): string {
  switch (p.type) {
    case 'string':
      return 'String'
    case 'number':
      return 'Number'
    // case 'integer':
    //   return 'Integer'
    // case 'nil':
    //   return 'Nil'
    case 'boolean':
      return 'Boolean'
    case 'date':
      return 'Date'
    case 'datetime':
      return 'Date and time'
    case 'time':
      return 'Time'
    // case 'any':
    //   return 'Any'
    case 'binary':
      return 'Binary'
    default:
      return 'Unknown'
  }
}

/**
 * Gathers information about the HTML input's requirements for the given DomainProperty.
 *
 * @param model The data property model to gather HTML input's configuration for.
 * @returns Input attributes to set.
 */
export function getPropertyInputOptions(model: DomainProperty): DomainPropertyInputConfig {
  const result: DomainPropertyInputConfig = { type: 'text' }
  if (model.type === 'date') {
    result.type = 'date'
    result.help = 'Date in YYYY-MM-DD format'
    return result
  }
  if (model.type === 'datetime') {
    result.type = 'datetime-local'
    result.help = 'Date and time in YYYY-MM-DDTHH:mm format'
    return result
  }
  if (model.type === 'time') {
    result.type = 'time'
    result.help = 'Time in HH:mm format'
    return result
  }
  if (model.type !== 'number') {
    return result
  }
  const schema = model.schema || {}
  const wb = model.getWebBinding()
  if (!wb) {
    return result
  }
  const format = wb.format
  if (format === 'float') {
    result.type = 'number'
    result.step = schema.multipleOf ?? 0.000001
    result.help = '32-bit number with decimals'
    return result
  }
  if (format === 'double') {
    result.type = 'number'
    result.step = schema.multipleOf ?? 0.000001
    result.help = '64-bit number with decimals'
    return result
  } else if (format === 'int32') {
    result.type = 'number'
    result.step = schema.multipleOf ?? 1
    result.help = '-2,147,483,648…+2,147,483,647 (32 bit)'
    result.min = -2147483648
    result.max = 2147483647
    return result
  } else if (format === 'int64') {
    result.type = 'number'
    result.step = schema.multipleOf ?? 1
    result.help = 'Negative or positive 64-bit integer'
    return result
  }
  return result
}

export function getFormatInfo(format: DomainPropertyFormat): { label: string; help: string } {
  if (format === 'float') {
    return { label: 'Float', help: '32-bit number with decimals' }
  }
  if (format === 'double') {
    return { label: 'Double', help: '64-bit number with decimals' }
  }
  if (format === 'int32') {
    return { label: 'Integer (32-bit)', help: '-2,147,483,648…+2,147,483,647' }
  }
  if (format === 'int64') {
    return { label: 'Integer (64-bit)', help: 'Negative or positive 64-bit integer' }
  }
  if (format === 'hex') {
    return { label: 'Hex', help: 'Hex-encoded binary data' }
  }
  if (format === 'base64') {
    return { label: 'Base64', help: 'Base64-encoded binary data' }
  }
  return { label: 'Unknown', help: 'An error occurred...' }
}

export function getDomainLabel(kind: string, options: { capitalize?: boolean } = {}): string {
  const { capitalize = false } = options
  let result = kind
  if (result === DomainNamespaceKind) {
    result = 'namespace'
  } else if (result === DomainModelKind) {
    result = 'model'
  } else if (result === DomainEntityKind) {
    result = 'entity'
  } else if (result === DomainPropertyKind) {
    result = 'property'
  } else if (result === DomainAssociationKind) {
    result = 'association'
  }
  if (!result) {
    return result
  }
  return capitalize ? result.charAt(0).toUpperCase() + result.slice(1) : result
}

/**
 * Gets the icon type for a given item kind.
 * @param kind - The kind of the item.
 * @returns The icon type.
 */
export function getDomainIconType(kind: string): IconType {
  if (kind === DomainModelKind) {
    return 'schemaModel'
  }
  if (kind === DomainNamespaceKind) {
    return 'schemaNamespace'
  }
  return 'schemaEntity'
}

/**
 * Maps an API Action kind to a user-friendly label.
 * @param kind The API Action kind.
 * @returns The label to render with the UI that correspond to the action.
 */
export function apiActionKindToLabel(kind: string): string {
  switch (kind) {
    case 'list':
      return 'List'
    case 'create':
      return 'Create'
    case 'read':
      return 'Read'
    case 'update':
      return 'Update'
    case 'delete':
      return 'Delete'
    case 'search':
      return 'Search'
    default:
      return 'Unknown'
  }
}

/**
 * Maps an API Action kind to an icon name.
 * @param kind The API Action kind.
 * @returns The icon name to use for the action kind.
 */
export function apiActionKindToIcon(kind: string): string {
  switch (kind) {
    case 'list':
      return 'list'
    case 'create':
      return 'add_box'
    case 'read':
      return 'get_app'
    case 'update':
      return 'edit'
    case 'delete':
      return 'delete'
    case 'search':
      return 'search'
    default:
      return 'help_circle'
  }
}
