/**
 * Composable for TerminusDB:
 * - Load schema by ID via GraphQL introspection
 * - Convert schema to FormKit format
 */

import type { FormKitSchemaNode } from '@formkit/core'

// Types for TerminusDB GraphQL introspection
interface TerminusField {
  name: string
  type: {
    name: string | null
    kind: string
    ofType?: {
      name: string | null
      kind: string
      enumValues?: Array<{ name: string }>
    }
    enumValues?: Array<{ name: string }>
  }
}

interface TerminusType {
  name: string
  kind: string
  description: string | null
  fields: TerminusField[] | null
  enumValues: Array<{ name: string }> | null
}

// Map GraphQL scalar types to FormKit types
const graphqlToFormKit: Record<string, string> = {
  'String': 'text',
  'Int': 'number',
  'Float': 'number',
  'Boolean': 'checkbox',
  'DateTime': 'datetime-local',
  'Date': 'date',
  'BigInt': 'number',
  'Decimal': 'number',
}

export function useTerminus() {
  const config = useRuntimeConfig()

  // TerminusDB GraphQL endpoint
  const getEndpoint = (): string => {
    return (config.public.terminusGraphql as string) || 'https://terminus.optovia.ru/api/graphql/admin/optovia'
  }

  // Basic auth header
  const getAuthHeader = () => {
    // admin:optovia_admin_2024 in base64
    return 'Basic ' + btoa('admin:optovia_admin_2024')
  }

  /**
   * Load schema from TerminusDB via GraphQL introspection
   */
  async function getSchema(schemaId: string): Promise<TerminusType | null> {
    try {
      const endpoint = getEndpoint()

      // GraphQL introspection query for a specific type
      const query = `
        query IntrospectionQuery {
          __type(name: "${schemaId}") {
            name
            kind
            description
            fields {
              name
              type {
                name
                kind
                ofType {
                  name
                  kind
                  enumValues {
                    name
                  }
                }
                enumValues {
                  name
                }
              }
            }
          }
        }
      `

      const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': getAuthHeader(),
        },
        body: JSON.stringify({ query }),
      })

      const result = await response.json() as { data: { __type: TerminusType | null } }
      return result.data?.__type || null
    } catch (error) {
      console.error('Failed to load schema from TerminusDB:', error)
      return null
    }
  }

  /**
   * Fetch all enums from schema via introspection
   */
  async function getEnums(): Promise<Record<string, string[]>> {
    try {
      const endpoint = getEndpoint()

      // Get all types and filter enums
      const query = `
        query IntrospectionQuery {
          __schema {
            types {
              name
              kind
              enumValues {
                name
              }
            }
          }
        }
      `

      const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': getAuthHeader(),
        },
        body: JSON.stringify({ query }),
      })

      const result = await response.json() as { data: { __schema: { types: TerminusType[] } } }

      const enums: Record<string, string[]> = {}

      for (const type of result.data?.__schema?.types || []) {
        // Keep only our enums (exclude system __)
        if (type.kind === 'ENUM' && !type.name.startsWith('__') && type.enumValues) {
          enums[type.name] = type.enumValues.map(e => e.name)
        }
      }

      return enums
    } catch (error) {
      console.error('Failed to load enums from TerminusDB:', error)
      return {}
    }
  }

  /**
   * Convert TerminusDB type to FormKit schema
   */
  function schemaToFormKit(
    terminusType: TerminusType,
    enums: Record<string, string[]>
  ): FormKitSchemaNode[] {
    const formkitSchema: FormKitSchemaNode[] = []

    if (!terminusType.fields) return formkitSchema

    // System fields to skip (TerminusDB internal fields start with _)
    const skipFields = ['id', '_id', '_type', '_json']
    // Also skip path fields like _path_to_Cocoa, _path_to_Coffee, etc.
    const isPathField = (name: string) => name.startsWith('_path_to_')

    for (const field of terminusType.fields) {
      if (skipFields.includes(field.name) || isPathField(field.name)) continue

      const formkitField = parseFieldType(field, enums)
      if (formkitField) {
        formkitSchema.push(formkitField)
      }
    }

    return formkitSchema
  }

  /**
   * Parse field type and build FormKit node
   */
  function parseFieldType(
    field: TerminusField,
    enums: Record<string, string[]>
  ): FormKitSchemaNode | null {
    const { name, type } = field

    // Determine actual type (may be wrapped in NON_NULL or LIST)
    let actualType = type
    let required = false

    if (type.kind === 'NON_NULL') {
      required = true
      actualType = type.ofType as typeof type
    }

    // Enum?
    if (actualType.kind === 'ENUM' && actualType.name) {
      const enumValues = actualType.enumValues?.map(e => e.name) || enums[actualType.name] || []
      return createSelectField(name, enumValues, required)
    }

    // Scalar type
    if (actualType.kind === 'SCALAR' && actualType.name) {
      return createInputField(name, actualType.name, required)
    }

    // LIST -> textarea
    if (actualType.kind === 'LIST') {
      return {
        $formkit: 'textarea',
        name,
        label: formatLabel(name),
        help: 'Enter values separated by comma',
        validation: required ? 'required' : undefined,
      }
    }

    return null
  }

  /**
   * Create input field
   */
  function createInputField(
    fieldName: string,
    graphqlType: string,
    required: boolean
  ): FormKitSchemaNode {
    const formkitType = graphqlToFormKit[graphqlType] || 'text'

    const field: FormKitSchemaNode = {
      $formkit: formkitType,
      name: fieldName,
      label: formatLabel(fieldName),
      validation: required ? 'required' : undefined,
    }

    // For Float/Decimal add step
    if (graphqlType === 'Float' || graphqlType === 'Decimal') {
      (field as Record<string, unknown>).step = '0.01'
    }

    return field
  }

  /**
   * Create select field from enum
   */
  function createSelectField(
    fieldName: string,
    options: string[],
    required: boolean
  ): FormKitSchemaNode {
    return {
      $formkit: 'select',
      name: fieldName,
      label: formatLabel(fieldName),
      validation: required ? 'required' : undefined,
      placeholder: 'Select...',
      options: options.map(opt => ({
        value: opt,
        label: formatLabel(opt),
      })),
    }
  }

  /**
   * Format field name to human-readable label
   */
  function formatLabel(fieldName: string): string {
    return fieldName
      .replace(/_/g, ' ')
      .replace(/([A-Z])/g, ' $1')
      .replace(/^\w/, c => c.toUpperCase())
      .trim()
  }

  return {
    getSchema,
    getEnums,
    schemaToFormKit,
    formatLabel,
    getEndpoint,
  }
}
