/**
 * FlowTool
 *
 * Built-in tool for the AI to interact with Flow state during autonomous development.
 * Allows the AI to query progress, report verification results, save checkpoints,
 * and advance through plan steps.
 */

import { z } from 'zod/v4'
import { buildTool } from '../../Tool.js'
import { lazySchema } from '../../utils/lazySchema.js'
import type { ToolResultBlockParam } from '@sandcode/sdk/resources/index.mjs'
import {
  getActiveFlow,
  getFlowStatus,
} from '../../services/FlowEngine/FlowEngine.js'
import { getForgeStatus, runForgeTests } from '../../services/Forge/ForgeDaemon.js'
import { saveCheckpoint } from '../../services/FlowEngine/checkpointManager.js'
import { getPlanProgress } from '../../services/FlowEngine/planDecomposer.js'
import { FLOW_TOOL_NAME, DESCRIPTION, PROMPT } from './prompt.js'

const inputSchema = lazySchema(() =>
  z.strictObject({
    action: z
      .enum(['status', 'report-verification', 'save-checkpoint', 'advance', 'report-failure'])
      .describe('The action to perform on the active flow'),
    stepIndex: z
      .number()
      .optional()
      .describe('Step index (for report-verification, advance, report-failure)'),
    passed: z
      .boolean()
      .optional()
      .describe('Whether verification passed (for report-verification)'),
    error: z
      .string()
      .optional()
      .describe('Error message (for report-failure)'),
    description: z
      .string()
      .optional()
      .describe('Description for checkpoint (for save-checkpoint)'),
  }),
)
type InputSchema = ReturnType<typeof inputSchema>

const outputSchema = lazySchema(() =>
  z.object({
    action: z.string(),
    result: z.string(),
    progress: z
      .object({
        completed: z.number(),
        total: z.number(),
        percentage: z.number(),
      })
      .optional(),
  }),
)
type OutputSchema = ReturnType<typeof outputSchema>

export const FlowTool = buildTool({
  name: FLOW_TOOL_NAME,
  searchHint: 'interact with autonomous flow state',
  maxResultSizeChars: 10_000,
  strict: true,
  async description() {
    return DESCRIPTION
  },
  async prompt() {
    return PROMPT
  },
  get inputSchema(): InputSchema {
    return inputSchema()
  },
  get outputSchema(): OutputSchema {
    return outputSchema()
  },
  userFacingName() {
    return 'Flow'
  },
  shouldDefer: true,
  isEnabled() {
    // Only enabled when there's an active flow
    return getActiveFlow() !== null
  },
  toAutoClassifierInput(input) {
    return input.action
  },
  async checkPermissions(input) {
    return { behavior: 'allow', updatedInput: input }
  },
  renderToolUseMessage() {
    return null
  },
  async call({ action, stepIndex, passed, error, description }, _context) {
    const state = getActiveFlow()

    if (!state) {
      return {
        data: {
          action,
          result: 'No active flow. Use /flow <intent> to start one.',
        },
      }
    }

    switch (action) {
      case 'status': {
        const statusText = getFlowStatus()
        const forgeStatus = getForgeStatus()
        const forgeText = forgeStatus.running
          ? `Forge: ${forgeStatus.runsCompleted} runs (${forgeStatus.runsPassed} passed, ${forgeStatus.runsFailed} failed)`
          : 'Forge: Not running'

        let progressInfo: { completed: number; total: number; percentage: number } | undefined
        if (state.plan) {
          progressInfo = getPlanProgress(state.plan)
        }

        return {
          data: {
            action,
            result: [statusText, forgeText].join('\n'),
            progress: progressInfo,
          },
        }
      }

      case 'report-verification': {
        const step = stepIndex !== undefined
          ? state.plan?.steps[stepIndex]
          : undefined

        if (!step) {
          return {
            data: {
              action,
              result: `Step ${stepIndex} not found in active plan.`,
            },
          }
        }

        if (passed) {
          step.status = 'completed'
          return {
            data: {
              action,
              result: `Step ${stepIndex} verified and passed.`,
              progress: state.plan ? getPlanProgress(state.plan) : undefined,
            },
          }
        }

        step.status = 'fixing'
        return {
          data: {
            action,
            result: `Step ${stepIndex} verification failed. Review errors and fix.`,
            progress: state.plan ? getPlanProgress(state.plan) : undefined,
          },
        }
      }

      case 'save-checkpoint': {
        const cpStepIndex = stepIndex ?? state.currentStepIndex
        const cpDescription = description ?? `Checkpoint at step ${cpStepIndex}`

        try {
          await saveCheckpoint(state, cpStepIndex, cpDescription, cpDescription)

          return {
            data: {
              action,
              result: `Checkpoint saved at step ${cpStepIndex}.`,
            },
          }
        } catch (e) {
          return {
            data: {
              action,
              result: `Failed to save checkpoint: ${e instanceof Error ? e.message : String(e)}`,
            },
          }
        }
      }

      case 'advance': {
        if (!state.plan) {
          return {
            data: {
              action,
              result: 'No plan to advance.',
            },
          }
        }

        const currentStepIdx = stepIndex ?? state.currentStepIndex
        const currentStep = state.plan.steps[currentStepIdx]

        if (currentStep) {
          currentStep.status = 'completed'
        }

        state.currentStepIndex = currentStepIdx + 1
        const progress = getPlanProgress(state.plan)

        if (progress.completed === progress.total) {
          return {
            data: {
              action,
              result: 'All steps completed! Flow is done.',
              progress,
            },
          }
        }

        return {
          data: {
            action,
            result: `Step ${currentStepIdx} completed. Next: step ${state.currentStepIndex}.`,
            progress,
          },
        }
      }

      case 'report-failure': {
        const failStep = stepIndex !== undefined
          ? state.plan?.steps[stepIndex]
          : undefined

        if (!failStep) {
          return {
            data: {
              action,
              result: `Step ${stepIndex} not found in active plan.`,
            },
          }
        }

        failStep.status = 'failed'
        failStep.lastError = error ?? 'Unknown error'
        failStep.iterations++

        return {
          data: {
            action,
            result: `Step ${stepIndex} failed: ${error ?? 'Unknown error'}. Iteration ${failStep.iterations}/${failStep.maxIterations}.`,
            progress: state.plan ? getPlanProgress(state.plan) : undefined,
          },
        }
      }

      default:
        return {
          data: {
            action,
            result: `Unknown action: ${action}`,
          },
        }
    }
  },
  mapToolResultToToolResultBlockParam({ action, result }, toolUseID): ToolResultBlockParam {
    return {
      tool_use_id: toolUseID,
      type: 'tool_result',
      content: `[Flow:${action}] ${result}`,
    }
  },
})

export type FlowToolOutput = z.infer<OutputSchema>
