/**
 * AI Schema Validation Test Fixtures
 * Tests for detecting missing/weak validation of AI-generated outputs
 */

import type { TestGroup } from '../../types'

export const aiSchemaValidationTests: TestGroup = {
  name: 'AI Schema Validation',
  tier: 'B',
  layer: 2,
  description: 'Detection of missing or weak schema validation on AI-generated outputs',

  truePositives: [
    {
      name: 'Schema Validation - True Positives',
      expectFindings: true,
      expectedCategories: ['ai_schema_mismatch'],
      description: 'Unvalidated AI output parsing that MUST be detected',
      file: {
        path: 'src/ai/chat-handler.ts',
        content: `
import OpenAI from 'openai'

const openai = new OpenAI()

// Unvalidated JSON.parse of AI response - MEDIUM
export async function getStructuredResponse(prompt: string) {
  const completion = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: prompt }],
  })

  // UNSAFE: No schema validation
  const data = JSON.parse(completion.choices[0].message.content)
  return data
}

// Tool call arguments parsed without validation - MEDIUM
export async function handleToolCall(toolCall: any) {
  const args = JSON.parse(toolCall.function.arguments)
  // Using args directly without validation
  return processArgs(args)
}

// Anthropic response parsed directly - MEDIUM
export async function handleAnthropicResponse(response: any) {
  const parsed = JSON.parse(response.content[0].text)
  return parsed.action
}

// AI response typed as any - LOW
export async function processAIOutput() {
  const response: any = await getAICompletion()
  // Using untyped response
  return response.result
}
`,
        language: 'typescript',
        size: 900,
      },
    },
    {
      name: 'Weak Schema Patterns',
      expectFindings: true,
      expectedCategories: ['ai_schema_mismatch'],
      description: 'Permissive schema patterns that provide inadequate validation',
      file: {
        path: 'src/ai/weak-schemas.ts',
        content: `
import { z } from 'zod'
import OpenAI from 'openai'

const openai = new OpenAI()

// Using z.any() defeats schema validation - LOW
const responseSchema = z.any()
const aiResponse = responseSchema.parse(completion.choices[0].message.content)

// Passthrough allowing extra properties - INFO
const dataSchema = z.object({
  action: z.string(),
}).passthrough()

// Record<string, any> for AI data - LOW
interface AIData {
  aiOutput: Record<string, any>
}

// Generic object type - INFO
function processResponse(completion: object) {
  return completion
}

// Any typed response at API boundary - MEDIUM (elevated)
export async function handler(req: Request) {
  const response: any = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: 'test' }],
  })
  return Response.json(response)
}
`,
        language: 'typescript',
        size: 700,
      },
    },
    {
      name: 'Tool Parameters in Security Sinks',
      expectFindings: true,
      expectedCategories: ['ai_schema_mismatch'],
      description: 'AI-generated tool parameters used in dangerous operations',
      file: {
        path: 'src/ai/tool-execution.ts',
        content: `
import { exec } from 'child_process'
import * as fs from 'fs'

// Tool parameter in shell command - CRITICAL
async function executeToolCommand(toolArgs: any) {
  const command = toolArgs.command
  exec(command, (error, stdout) => {
    console.log(stdout)
  })
}

// Tool parameter in file path - HIGH
async function readToolFile(args: { path: string }) {
  const filePath = args.path
  const content = fs.readFileSync(filePath, 'utf-8')
  return content
}

// Tool parameter in database query - HIGH
async function queryFromTool(parameters: any, db: any) {
  const tableName = parameters.table
  const results = await db.query(\`SELECT * FROM \${tableName}\`)
  return results
}

// Tool parameter in URL - HIGH
async function fetchToolUrl(args: any) {
  const endpoint = args.url
  const response = await fetch(endpoint)
  return response.json()
}

// Function name routing without validation - MEDIUM
async function routeToolCall(tool_call: any) {
  const name = tool_call.function.name
  switch (name) {
    case 'search': return search()
    default: return functions[name]() // Dynamic access
  }
}
`,
        language: 'typescript',
        size: 950,
      },
    },
  ],

  falseNegatives: [
    {
      name: 'Schema Validation - False Negatives',
      expectFindings: false,
      description: 'Properly validated AI outputs that should NOT be flagged',
      allowedInfoFindings: [
        {
          category: 'ai_schema_mismatch',
          maxCount: 2,
          reason: 'Some patterns may generate info-level findings even when properly handled',
        },
        {
          category: 'dangerous_function',
          maxCount: 2,
          reason: 'JSON.parse with schema validation nearby may still trigger info-level findings',
        },
      ],
      file: {
        path: 'src/ai/validated-handler.ts',
        content: `
import OpenAI from 'openai'
import { z } from 'zod'

const openai = new OpenAI()

// Proper schema definition
const ResponseSchema = z.object({
  action: z.enum(['search', 'create', 'delete']),
  target: z.string().min(1),
  params: z.record(z.string()).optional(),
}).strict()

// Validated AI response parsing - SAFE
export async function getValidatedResponse(prompt: string) {
  const completion = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: prompt }],
  })

  // Schema validation with zod
  const validated = ResponseSchema.parse(
    JSON.parse(completion.choices[0].message.content!)
  )

  return validated
}

// safeParse with error handling - SAFE
export async function getSafeResponse(prompt: string) {
  const raw = await getAICompletion(prompt)
  const result = ResponseSchema.safeParse(JSON.parse(raw))

  if (!result.success) {
    throw new Error('Invalid AI response: ' + result.error.message)
  }

  return result.data
}

// Tool arguments with schema validation - SAFE
const ToolArgsSchema = z.object({
  query: z.string(),
  limit: z.number().int().positive().max(100),
})

export async function handleToolWithValidation(toolCall: any) {
  const args = ToolArgsSchema.parse(
    JSON.parse(toolCall.function.arguments)
  )
  return search(args.query, args.limit)
}

// OpenAI Structured Outputs - SAFE
export async function getStructuredOutput(prompt: string) {
  const completion = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: prompt }],
    response_format: {
      type: 'json_schema',
      json_schema: {
        name: 'response',
        schema: {
          type: 'object',
          properties: {
            action: { type: 'string' },
            target: { type: 'string' },
          },
          required: ['action', 'target'],
        },
      },
    },
  })

  return JSON.parse(completion.choices[0].message.content!)
}
`,
        language: 'typescript',
        size: 1700,
      },
    },
    {
      name: 'Tool Parameters with Allowlist',
      expectFindings: false,
      description: 'Tool parameters validated against allowlists',
      allowedInfoFindings: [
        {
          category: 'ai_schema_mismatch',
          maxCount: 1,
          reason: 'May flag routing pattern at info level',
        },
        {
          category: 'dangerous_function',
          maxCount: 2,
          reason: 'fs operations may trigger info-level findings',
        },
        {
          category: 'ai_unsafe_execution',
          maxCount: 2,
          reason: 'File operations with proper validation may still flag at low severity',
        },
      ],
      file: {
        path: 'src/ai/safe-tool-execution.ts',
        content: `
import * as path from 'path'
import * as fs from 'fs'
import { z } from 'zod'

// Allowlisted commands - SAFE
const ALLOWED_COMMANDS = ['ls', 'cat', 'echo'] as const
const CommandSchema = z.enum(ALLOWED_COMMANDS)

async function executeAllowlistedCommand(args: { cmd: string }) {
  const validated = CommandSchema.parse(args.cmd)
  // Only allowed commands can execute
  return runCommand(validated)
}

// Path validation with allowlist - SAFE
const ALLOWED_PATHS = ['/app/data', '/app/uploads']

async function readAllowlistedFile(args: { filePath: string }) {
  const resolved = path.resolve(args.filePath)

  // Validate path against allowlist
  if (!ALLOWED_PATHS.some(p => resolved.startsWith(p))) {
    throw new Error('Path not allowed')
  }

  return fs.readFileSync(resolved, 'utf-8')
}

// URL validation against allowed hosts - SAFE
const ALLOWED_HOSTS = ['api.example.com', 'data.example.com']

async function fetchAllowlistedUrl(args: { url: string }) {
  const parsed = new URL(args.url)

  if (!ALLOWED_HOSTS.includes(parsed.host)) {
    throw new Error('Host not allowed')
  }

  return fetch(args.url)
}

// Function routing with explicit allowlist - SAFE
const ALLOWED_FUNCTIONS = ['search', 'calculate', 'format'] as const
type AllowedFunction = typeof ALLOWED_FUNCTIONS[number]

const handlers: Record<AllowedFunction, () => void> = {
  search: () => {},
  calculate: () => {},
  format: () => {},
}

async function routeWithAllowlist(toolCall: { name: string }) {
  const name = toolCall.name as AllowedFunction

  if (!ALLOWED_FUNCTIONS.includes(name)) {
    throw new Error('Function not allowed: ' + name)
  }

  return handlers[name]()
}
`,
        language: 'typescript',
        size: 1400,
      },
    },
    {
      name: 'Strongly Typed AI Interfaces',
      expectFindings: false,
      description: 'Properly typed AI responses with strict interfaces',
      allowedInfoFindings: [
        {
          category: 'ai_schema_mismatch',
          maxCount: 1,
          reason: 'Type-only patterns may still flag for runtime validation',
        },
        {
          category: 'dangerous_function',
          maxCount: 2,
          reason: 'JSON.parse with schema validation nearby may still trigger info-level findings',
        },
      ],
      file: {
        path: 'src/ai/typed-responses.ts',
        content: `
import OpenAI from 'openai'
import { z } from 'zod'

// Strict interface definition
interface AISearchResult {
  query: string
  results: Array<{
    id: string
    title: string
    score: number
  }>
  metadata: {
    processingTime: number
    model: string
  }
}

// Runtime validation with zod matching interface
const AISearchResultSchema = z.object({
  query: z.string(),
  results: z.array(z.object({
    id: z.string(),
    title: z.string(),
    score: z.number().min(0).max(1),
  })),
  metadata: z.object({
    processingTime: z.number(),
    model: z.string(),
  }),
}).strict()

// Type-safe handler - SAFE
export async function searchWithAI(
  query: string,
  openai: OpenAI
): Promise<AISearchResult> {
  const completion = await openai.chat.completions.create({
    model: 'gpt-4',
    messages: [{ role: 'user', content: query }],
  })

  // Runtime validation ensures type safety
  const validated = AISearchResultSchema.parse(
    JSON.parse(completion.choices[0].message.content!)
  )

  return validated
}

// Generic with constraint - SAFE
export async function getTypedResponse<T>(
  schema: z.ZodSchema<T>,
  prompt: string
): Promise<T> {
  const raw = await getCompletion(prompt)
  return schema.parse(JSON.parse(raw))
}
`,
        language: 'typescript',
        size: 1200,
      },
    },
  ],
}
