import type { CommandEffect } from '@/framework/command'
import { DifyCommand } from '@/commands/_shared/dify-command'
import { httpRetryFlag } from '@/commands/_shared/global-flags'
import { Args, Flags } from '@/framework/flags'
import { OutputFormat } from '@/framework/output'
import { agentGuide } from './guide'
import { runApp } from './run'

export default class RunApp extends DifyCommand {
  static override description = 'Run an app and print the response'

  static override effect: CommandEffect = 'write'

  static override examples = [
    '<%= config.bin %> run app app-1 "hello"',
    '<%= config.bin %> run app app-1 --inputs \'{"name":"world"}\'',
    '<%= config.bin %> run app app-1 --inputs-file inputs.json',
    '<%= config.bin %> run app app-1 --stream',
    '<%= config.bin %> run app app-1 -o json',
    '<%= config.bin %> run app app-1 --file doc=@./report.pdf',
    '<%= config.bin %> run app app-1 --file img=https://cdn.example.com/logo.png',
  ]

  static override args = {
    id: Args.string({ description: 'app id', required: true }),
    message: Args.string({ description: 'user message (chat/agent-chat/advanced-chat/completion)', required: false }),
  }

  static override flags = {
    'inputs': Flags.string({ description: 'Input variables as a JSON object, e.g. --inputs \'{"key":"value"}\'. Mutually exclusive with --inputs-file.' }),
    'inputs-file': Flags.string({ description: 'Path to a JSON file containing the inputs object. Mutually exclusive with --inputs.' }),
    'file': Flags.stringArray({ description: 'Named file input: --file key=@path for a local file or --file key=https://url for a remote URL. Repeatable.', default: [] }),
    'conversation': Flags.string({ description: 'Resume a chat conversation by id (chat/advanced-chat only)' }),
    'workflow-id': Flags.string({ description: 'Pin to a specific published workflow version' }),
    'workspace': Flags.string({ description: 'Workspace id (overrides DIFY_WORKSPACE_ID and stored default)' }),
    'stream': Flags.boolean({ description: 'Print output live as tokens/events arrive (default: collect and print at end)', default: false }),
    'think': Flags.boolean({ description: 'Show model thinking/reasoning when available. Strips <think>...</think> blocks silently by default; with --think, thinking is printed to stderr.', default: false }),
    'retry-on-limit': Flags.boolean({ description: 'On a 429 rate limit, wait and retry this POST (bounded) instead of failing immediately. Off by default since running an app is not idempotent.', default: false }),
    'http-retry': httpRetryFlag,
    'output': Flags.outputFormat({ options: [OutputFormat.JSON, OutputFormat.YAML, OutputFormat.TEXT], default: '' }),
  }

  async run(argv: string[]): Promise<void> {
    const { args, flags } = this.parse(RunApp, argv)
    const format = flags.output
    const ctx = await this.authedCtx({ retryFlag: flags['http-retry'], withCache: true, format })
    await runApp(
      {
        appId: args.id,
        message: args.message,
        inputsJson: flags.inputs,
        inputsFile: flags['inputs-file'],
        files: flags.file,
        conversationId: flags.conversation,
        workflowId: flags['workflow-id'],
        workspace: flags.workspace,
        format,
        stream: flags.stream,
        think: flags.think,
        retryOnRateLimit: flags['retry-on-limit'],
      },
      { active: ctx.active, http: ctx.http, host: ctx.host, io: ctx.io, cache: ctx.cache },
    )
  }

  override agentGuide(): string {
    return agentGuide
  }
}
