'use server'

import { revalidatePath } from 'next/cache'
import { createClient } from '@/lib/supabase/server'
import { getUserSession } from '@/lib/auth/permissions'
import type { RoleCode } from '@/lib/auth/permissions-shared'
import {
  validateDefinitionInput,
  validateUpdateDefinitionInput,
  validateOptionInput,
  SELECT_TYPES,
  type DefinitionInput,
  type FieldDefinition,
  type FieldOption,
  type FieldType,
  type OptionInput,
  type UpdateDefinitionInput,
} from '@/lib/intake/field-builder'

const ADMIN_ROLES: ReadonlySet<RoleCode> = new Set(['admin', 'masteradmin'])

export type ActionResult<T = unknown> =
  | { ok: true; data?: T }
  | { ok: false; error: string }

async function requireAdmin(): Promise<
  { ok: true; userId: string } | { ok: false; error: string }
> {
  const session = await getUserSession()
  if (!session) return { ok: false, error: 'unauthorized' }
  if (!ADMIN_ROLES.has(session.role)) return { ok: false, error: 'forbidden' }
  return { ok: true, userId: session.authUserId }
}

export async function loadFieldDefinitions(): Promise<ActionResult<FieldDefinition[]>> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const supabase = await createClient()
  const { data, error } = await supabase
    .from('intake_field_definitions')
    .select(
      'id, field_key, block, sort_order, label_de, label_en, helptext_de, helptext_en, field_type, is_required, is_active, visible_if',
    )
    .order('block', { ascending: true })
    .order('sort_order', { ascending: true })

  if (error) return { ok: false, error: error.message }
  return { ok: true, data: (data ?? []) as FieldDefinition[] }
}

export async function loadFieldOptions(
  fieldDefinitionId: string,
): Promise<ActionResult<FieldOption[]>> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const supabase = await createClient()
  const { data, error } = await supabase
    .from('intake_field_options')
    .select('id, field_definition_id, option_value, label_de, label_en, sort_order, is_active')
    .eq('field_definition_id', fieldDefinitionId)
    .order('sort_order', { ascending: true })

  if (error) return { ok: false, error: error.message }
  return { ok: true, data: (data ?? []) as FieldOption[] }
}

export async function createFieldDefinition(
  input: DefinitionInput,
): Promise<ActionResult<{ id: string }>> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const validation = validateDefinitionInput(input)
  if (!validation.ok) return { ok: false, error: validation.error }

  const supabase = await createClient()
  const { data, error } = await supabase
    .from('intake_field_definitions')
    .insert({
      field_key: input.field_key.trim(),
      block: input.block,
      sort_order: input.sort_order,
      label_de: input.label_de.trim(),
      label_en: input.label_en?.trim() || null,
      helptext_de: input.helptext_de?.trim() || null,
      helptext_en: input.helptext_en?.trim() || null,
      field_type: input.field_type,
      is_required: input.is_required,
      visible_if: validation.visibleIf,
      is_active: true,
    })
    .select('id')
    .single()

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true, data: { id: data.id as string } }
}

export async function updateFieldDefinition(
  id: string,
  input: UpdateDefinitionInput,
): Promise<ActionResult> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const validation = validateUpdateDefinitionInput(input)
  if (!validation.ok) return { ok: false, error: validation.error }

  const supabase = await createClient()
  const { error } = await supabase
    .from('intake_field_definitions')
    .update({
      block: input.block,
      sort_order: input.sort_order,
      label_de: input.label_de.trim(),
      label_en: input.label_en?.trim() || null,
      helptext_de: input.helptext_de?.trim() || null,
      helptext_en: input.helptext_en?.trim() || null,
      is_required: input.is_required,
      is_active: input.is_active,
      visible_if: validation.visibleIf,
      updated_at: new Date().toISOString(),
    })
    .eq('id', id)

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true }
}

export async function setFieldDefinitionActive(
  id: string,
  isActive: boolean,
): Promise<ActionResult> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const supabase = await createClient()
  const { error } = await supabase
    .from('intake_field_definitions')
    .update({ is_active: isActive, updated_at: new Date().toISOString() })
    .eq('id', id)

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true }
}

export async function setFieldDefinitionRequired(
  id: string,
  isRequired: boolean,
): Promise<ActionResult> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const supabase = await createClient()
  const { error } = await supabase
    .from('intake_field_definitions')
    .update({ is_required: isRequired, updated_at: new Date().toISOString() })
    .eq('id', id)

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true }
}

export async function moveFieldDefinitionSortOrder(
  id: string,
  delta: number,
): Promise<ActionResult<{ sort_order: number }>> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth
  if (!Number.isInteger(delta) || (delta !== 1 && delta !== -1)) {
    return { ok: false, error: 'invalid_delta' }
  }

  const supabase = await createClient()
  const { data: existing, error: readErr } = await supabase
    .from('intake_field_definitions')
    .select('sort_order')
    .eq('id', id)
    .single()

  if (readErr || !existing) return { ok: false, error: readErr?.message ?? 'not_found' }

  const newSort = Math.max(0, (existing.sort_order as number) + delta)
  const { error: updateErr } = await supabase
    .from('intake_field_definitions')
    .update({ sort_order: newSort, updated_at: new Date().toISOString() })
    .eq('id', id)

  if (updateErr) return { ok: false, error: updateErr.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true, data: { sort_order: newSort } }
}

export async function createFieldOption(
  fieldDefinitionId: string,
  fieldType: FieldType,
  input: OptionInput,
): Promise<ActionResult<{ id: string }>> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  if (!SELECT_TYPES.has(fieldType)) return { ok: false, error: 'field_type_has_no_options' }
  const validation = validateOptionInput(input)
  if (!validation.ok) return { ok: false, error: validation.error }

  const supabase = await createClient()
  const { data, error } = await supabase
    .from('intake_field_options')
    .insert({
      field_definition_id: fieldDefinitionId,
      option_value: input.option_value.trim(),
      label_de: input.label_de.trim(),
      label_en: input.label_en?.trim() || null,
      sort_order: input.sort_order,
      is_active: input.is_active,
    })
    .select('id')
    .single()

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true, data: { id: data.id as string } }
}

export async function updateFieldOption(
  optionId: string,
  input: OptionInput,
): Promise<ActionResult> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const validation = validateOptionInput(input)
  if (!validation.ok) return { ok: false, error: validation.error }

  const supabase = await createClient()
  const { error } = await supabase
    .from('intake_field_options')
    .update({
      option_value: input.option_value.trim(),
      label_de: input.label_de.trim(),
      label_en: input.label_en?.trim() || null,
      sort_order: input.sort_order,
      is_active: input.is_active,
    })
    .eq('id', optionId)

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true }
}

export async function deleteFieldOption(optionId: string): Promise<ActionResult> {
  const auth = await requireAdmin()
  if (!auth.ok) return auth

  const supabase = await createClient()
  const { error } = await supabase.from('intake_field_options').delete().eq('id', optionId)

  if (error) return { ok: false, error: error.message }

  revalidatePath('/admin/intake-fields')
  return { ok: true }
}
