// Pure state machine for the question UI.
//
// Supports both single-question and multi-question flows. Single questions
// submit immediately on selection. Multi-question flows use tabs and a
// final confirmation step.
//
// State transitions:
//   questionSelect  → picks an option (single: submits, multi: toggles/advances)
//   questionSave    → saves custom text input
//   questionMove    → arrow key navigation through options
//   questionSetTab  → tab navigation between questions
//   questionSubmit  → builds the final QuestionReply with all answers
//
// Custom answers: if a question has custom=true, an extra "Type your own
// answer" option appears. Selecting it enters editing mode with a text field.
import type { QuestionInfo, QuestionRequest } from "@codilore/sdk/v2"
import type { QuestionReject, QuestionReply } from "./types"

export type QuestionBodyState = {
  requestID: string
  tab: number
  answers: string[][]
  custom: string[]
  selected: number
  editing: boolean
  submitting: boolean
}

export type QuestionStep = {
  state: QuestionBodyState
  reply?: QuestionReply
}

export function createQuestionBodyState(requestID: string): QuestionBodyState {
  return {
    requestID,
    tab: 0,
    answers: [],
    custom: [],
    selected: 0,
    editing: false,
    submitting: false,
  }
}

export function questionSync(state: QuestionBodyState, requestID: string): QuestionBodyState {
  if (state.requestID === requestID) {
    return state
  }

  return createQuestionBodyState(requestID)
}

export function questionSingle(request: QuestionRequest): boolean {
  return request.questions.length === 1 && request.questions[0]?.multiple !== true
}

export function questionTabs(request: QuestionRequest): number {
  return questionSingle(request) ? 1 : request.questions.length + 1
}

export function questionConfirm(request: QuestionRequest, state: QuestionBodyState): boolean {
  return !questionSingle(request) && state.tab === request.questions.length
}

export function questionInfo(request: QuestionRequest, state: QuestionBodyState): QuestionInfo | undefined {
  return request.questions[state.tab]
}

export function questionCustom(request: QuestionRequest, state: QuestionBodyState): boolean {
  return questionInfo(request, state)?.custom !== false
}

export function questionInput(state: QuestionBodyState): string {
  return state.custom[state.tab] ?? ""
}

export function questionPicked(state: QuestionBodyState): boolean {
  const value = questionInput(state)
  if (!value) {
    return false
  }

  return state.answers[state.tab]?.includes(value) ?? false
}

export function questionOther(request: QuestionRequest, state: QuestionBodyState): boolean {
  const info = questionInfo(request, state)
  if (!info || info.custom === false) {
    return false
  }

  return state.selected === info.options.length
}

export function questionTotal(request: QuestionRequest, state: QuestionBodyState): number {
  const info = questionInfo(request, state)
  if (!info) {
    return 0
  }

  return info.options.length + (questionCustom(request, state) ? 1 : 0)
}

export function questionAnswers(state: QuestionBodyState, count: number): string[][] {
  return Array.from({ length: count }, (_, idx) => state.answers[idx] ?? [])
}

export function questionSetTab(state: QuestionBodyState, tab: number): QuestionBodyState {
  return {
    ...state,
    tab,
    selected: 0,
    editing: false,
  }
}

export function questionSetSelected(state: QuestionBodyState, selected: number): QuestionBodyState {
  return {
    ...state,
    selected,
  }
}

export function questionSetEditing(state: QuestionBodyState, editing: boolean): QuestionBodyState {
  return {
    ...state,
    editing,
  }
}

export function questionSetSubmitting(state: QuestionBodyState, submitting: boolean): QuestionBodyState {
  return {
    ...state,
    submitting,
  }
}

function storeAnswers(state: QuestionBodyState, tab: number, list: string[]): QuestionBodyState {
  const answers = [...state.answers]
  answers[tab] = list
  return {
    ...state,
    answers,
  }
}

export function questionStoreCustom(state: QuestionBodyState, tab: number, text: string): QuestionBodyState {
  const custom = [...state.custom]
  custom[tab] = text
  return {
    ...state,
    custom,
  }
}

function questionPick(
  state: QuestionBodyState,
  request: QuestionRequest,
  answer: string,
  custom = false,
): QuestionStep {
  const answers = [...state.answers]
  answers[state.tab] = [answer]
  let next: QuestionBodyState = {
    ...state,
    answers,
    editing: false,
  }

  if (custom) {
    const list = [...state.custom]
    list[state.tab] = answer
    next = {
      ...next,
      custom: list,
    }
  }

  if (questionSingle(request)) {
    return {
      state: next,
      reply: {
        requestID: request.id,
        answers: [[answer]],
      },
    }
  }

  return {
    state: questionSetTab(next, state.tab + 1),
  }
}

function questionToggle(state: QuestionBodyState, answer: string): QuestionBodyState {
  const list = [...(state.answers[state.tab] ?? [])]
  const idx = list.indexOf(answer)
  if (idx === -1) {
    list.push(answer)
  } else {
    list.splice(idx, 1)
  }

  return storeAnswers(state, state.tab, list)
}

export function questionMove(state: QuestionBodyState, request: QuestionRequest, dir: -1 | 1): QuestionBodyState {
  const total = questionTotal(request, state)
  if (total === 0) {
    return state
  }

  return {
    ...state,
    selected: (state.selected + dir + total) % total,
  }
}

export function questionSelect(state: QuestionBodyState, request: QuestionRequest): QuestionStep {
  const info = questionInfo(request, state)
  if (!info) {
    return { state }
  }

  if (questionOther(request, state)) {
    if (!info.multiple) {
      return {
        state: questionSetEditing(state, true),
      }
    }

    const value = questionInput(state)
    if (value && questionPicked(state)) {
      return {
        state: questionToggle(state, value),
      }
    }

    return {
      state: questionSetEditing(state, true),
    }
  }

  const option = info.options[state.selected]
  if (!option) {
    return { state }
  }

  if (info.multiple) {
    return {
      state: questionToggle(state, option.label),
    }
  }

  return questionPick(state, request, option.label)
}

export function questionSave(state: QuestionBodyState, request: QuestionRequest): QuestionStep {
  const info = questionInfo(request, state)
  if (!info) {
    return { state }
  }

  const value = questionInput(state).trim()
  const prev = state.custom[state.tab]
  if (!value) {
    if (!prev) {
      return {
        state: questionSetEditing(state, false),
      }
    }

    const next = questionStoreCustom(state, state.tab, "")
    return {
      state: questionSetEditing(
        storeAnswers(
          next,
          state.tab,
          (state.answers[state.tab] ?? []).filter((item) => item !== prev),
        ),
        false,
      ),
    }
  }

  if (info.multiple) {
    const answers = [...(state.answers[state.tab] ?? [])]
    if (prev) {
      const idx = answers.indexOf(prev)
      if (idx !== -1) {
        answers.splice(idx, 1)
      }
    }

    if (!answers.includes(value)) {
      answers.push(value)
    }

    const next = questionStoreCustom(state, state.tab, value)
    return {
      state: questionSetEditing(storeAnswers(next, state.tab, answers), false),
    }
  }

  return questionPick(state, request, value, true)
}

export function questionSubmit(request: QuestionRequest, state: QuestionBodyState): QuestionReply {
  return {
    requestID: request.id,
    answers: questionAnswers(state, request.questions.length),
  }
}

export function questionReject(request: QuestionRequest): QuestionReject {
  return {
    requestID: request.id,
  }
}

export function questionHint(request: QuestionRequest, state: QuestionBodyState): string {
  if (state.submitting) {
    return "Waiting for question event..."
  }

  if (questionConfirm(request, state)) {
    return "enter submit   esc dismiss"
  }

  if (state.editing) {
    return "enter save   esc cancel"
  }

  const info = questionInfo(request, state)
  if (questionSingle(request)) {
    return `↑↓ select   enter ${info?.multiple ? "toggle" : "submit"}   esc dismiss`
  }

  return `⇆ tab   ↑↓ select   enter ${info?.multiple ? "toggle" : "confirm"}   esc dismiss`
}
