import { describe, it, expect } from 'vitest'
import {
  FormFieldSchema,
  FormSchemaSchema,
  ActionConfigSchema,
  CreateTaskParamsSchema,
  PatchTaskRequestSchema,
  SubmitActionParamsSchema,
  validateActions,
  validateActionConfig,
  validateFormSchema,
  validateFormField
} from './schemas'
import type { ActionConfig, FormField, FormSchema } from './types'

describe('FormFieldSchema', () => {
  it('validates a valid text field', () => {
    const field: FormField = {
      name: 'email',
      label: 'Email Address',
      type: 'text',
      required: true,
      placeholder: 'you@example.com'
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('validates a valid number field with min/max', () => {
    const field: FormField = {
      name: 'age',
      label: 'Age',
      type: 'number',
      min: 18,
      max: 100
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('validates a valid select field with options', () => {
    const field: FormField = {
      name: 'priority',
      label: 'Priority',
      type: 'select',
      options: [
        { label: 'Low', value: 'low' },
        { label: 'High', value: 'high' }
      ]
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('validates a valid radio field with options', () => {
    const field: FormField = {
      name: 'choice',
      label: 'Choose One',
      type: 'radio',
      options: [
        { label: 'Option A', value: 1 },
        { label: 'Option B', value: 2 }
      ]
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('validates a valid checkbox field', () => {
    const field: FormField = {
      name: 'agree',
      label: 'I agree to terms',
      type: 'checkbox',
      defaultValue: false
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('validates a valid textarea field', () => {
    const field: FormField = {
      name: 'notes',
      label: 'Notes',
      type: 'textarea',
      placeholder: 'Enter your notes...',
      description: 'Optional notes'
    }

    expect(() => FormFieldSchema.parse(field)).not.toThrow()
  })

  it('rejects field with empty name', () => {
    const field = {
      name: '',
      label: 'Label',
      type: 'text'
    }

    expect(() => FormFieldSchema.parse(field)).toThrow()
  })

  it('rejects field with empty label', () => {
    const field = {
      name: 'field',
      label: '',
      type: 'text'
    }

    expect(() => FormFieldSchema.parse(field)).toThrow()
  })

  it('rejects field with invalid type', () => {
    const field = {
      name: 'field',
      label: 'Label',
      type: 'invalid'
    }

    expect(() => FormFieldSchema.parse(field)).toThrow()
  })

  it('rejects select field without options', () => {
    const field = {
      name: 'choice',
      label: 'Choose',
      type: 'select'
    }

    expect(() => FormFieldSchema.parse(field)).toThrow()
  })

  it('rejects radio field without options', () => {
    const field = {
      name: 'choice',
      label: 'Choose',
      type: 'radio',
      options: []
    }

    expect(() => FormFieldSchema.parse(field)).toThrow()
  })
})

describe('FormSchemaSchema', () => {
  it('validates a valid form schema', () => {
    const schema: FormSchema = {
      title: 'User Form',
      description: 'Please fill out this form',
      fields: [
        { name: 'name', label: 'Name', type: 'text', required: true },
        { name: 'age', label: 'Age', type: 'number', min: 0 }
      ],
      layout: 'vertical'
    }

    expect(() => FormSchemaSchema.parse(schema)).not.toThrow()
  })

  it('validates form with minimal fields', () => {
    const schema: FormSchema = {
      fields: [{ name: 'field1', label: 'Field 1', type: 'text' }]
    }

    expect(() => FormSchemaSchema.parse(schema)).not.toThrow()
  })

  it('rejects form with empty fields array', () => {
    const schema = {
      fields: []
    }

    expect(() => FormSchemaSchema.parse(schema)).toThrow()
  })

  it('strips unknown fields (Zod default behavior)', () => {
    const schema = {
      fields: [{ name: 'field', label: 'Field', type: 'text' }],
      layout: 'invalid'
    }

    // Zod strips unknown keys by default (no .strict()), so extra fields don't cause errors
    const result = FormSchemaSchema.parse(schema)
    expect(result).not.toHaveProperty('layout')
  })
})

describe('ActionConfigSchema', () => {
  it('validates a minimal action config', () => {
    const action: ActionConfig = {
      id: 'approve',
      label: 'Approve',
      type: 'primary'
    }

    expect(() => ActionConfigSchema.parse(action)).not.toThrow()
  })

  it('validates an action with target', () => {
    const action: ActionConfig = {
      id: 'approve',
      label: 'Approve',
      type: 'primary',
      icon: 'IconCheck',
      color: 'green',
      target: {
        resourceType: 'agent',
        resourceId: 'approval-handler'
      }
    }

    expect(() => ActionConfigSchema.parse(action)).not.toThrow()
  })

  it('validates an action with form', () => {
    const action: ActionConfig = {
      id: 'approve-with-changes',
      label: 'Approve with Changes',
      type: 'secondary',
      form: {
        title: 'Specify Changes',
        fields: [{ name: 'changes', label: 'Changes', type: 'textarea', required: true }]
      },
      target: {
        resourceType: 'workflow',
        resourceId: 'apply-changes'
      }
    }

    expect(() => ActionConfigSchema.parse(action)).not.toThrow()
  })

  it('validates an action with confirmation', () => {
    const action: ActionConfig = {
      id: 'delete',
      label: 'Delete',
      type: 'danger',
      requiresConfirmation: true,
      confirmationMessage: 'Are you sure you want to delete this?',
      description: 'This action cannot be undone'
    }

    expect(() => ActionConfigSchema.parse(action)).not.toThrow()
  })

  it('rejects action with empty id', () => {
    const action = {
      id: '',
      label: 'Action',
      type: 'primary'
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })

  it('rejects action with invalid id format', () => {
    const action = {
      id: 'Invalid_ID',
      label: 'Action',
      type: 'primary'
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })

  it('rejects action with empty label', () => {
    const action = {
      id: 'action',
      label: '',
      type: 'primary'
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })

  it('rejects action with invalid type', () => {
    const action = {
      id: 'action',
      label: 'Action',
      type: 'invalid'
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })

  it('rejects action with invalid target resource type', () => {
    const action = {
      id: 'action',
      label: 'Action',
      type: 'primary',
      target: {
        resourceType: 'invalid',
        resourceId: 'resource'
      }
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })

  it('rejects action with empty target resource id', () => {
    const action = {
      id: 'action',
      label: 'Action',
      type: 'primary',
      target: {
        resourceType: 'agent',
        resourceId: ''
      }
    }

    expect(() => ActionConfigSchema.parse(action)).toThrow()
  })
})

describe('CreateTaskParamsSchema', () => {
  const validParams = {
    organizationId: '123e4567-e89b-12d3-a456-426614174000',
    originExecutionId: 'exec-123',
    originResourceType: 'agent',
    originResourceId: 'test-agent',
    actions: [{ id: 'approve', label: 'Approve', type: 'primary' as const }],
    context: { data: 'test' },
    priority: 5
  }

  it('validates valid create task params', () => {
    expect(() => CreateTaskParamsSchema.parse(validParams)).not.toThrow()
  })

  it('validates with minimal params', () => {
    const minimal = {
      organizationId: '123e4567-e89b-12d3-a456-426614174000',
      originExecutionId: 'exec-123',
      originResourceType: 'agent',
      originResourceId: 'test-agent',
      actions: [{ id: 'approve', label: 'Approve', type: 'primary' as const }],
      context: { data: 'test' }
    }

    expect(() => CreateTaskParamsSchema.parse(minimal)).not.toThrow()
  })

  it('validates with maximum actions (20)', () => {
    const actions = Array.from({ length: 20 }, (_, i) => ({
      id: `action-${i}`,
      label: `Action ${i}`,
      type: 'primary' as const
    }))

    const params = { ...validParams, actions }

    expect(() => CreateTaskParamsSchema.parse(params)).not.toThrow()
  })

  it('rejects with invalid organization id', () => {
    const params = { ...validParams, organizationId: 'invalid-uuid' }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with empty actions array', () => {
    const params = { ...validParams, actions: [] }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with too many actions (>20)', () => {
    const actions = Array.from({ length: 21 }, (_, i) => ({
      id: `action-${i}`,
      label: `Action ${i}`,
      type: 'primary' as const
    }))

    const params = { ...validParams, actions }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with null context', () => {
    const params = { ...validParams, context: null }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with undefined context', () => {
    const params = { ...validParams, context: undefined }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with invalid priority (too low)', () => {
    const params = { ...validParams, priority: 0 }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with invalid priority (too high)', () => {
    const params = { ...validParams, priority: 11 }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })

  it('rejects with non-integer priority', () => {
    const params = { ...validParams, priority: 5.5 }

    expect(() => CreateTaskParamsSchema.parse(params)).toThrow()
  })
})

describe('PatchTaskRequestSchema', () => {
  it('accepts context only', () => {
    expect(() =>
      PatchTaskRequestSchema.parse({
        context: { lead: { senderName: 'Amy' }, email: { emailAccount: 'test@example.com' } }
      })
    ).not.toThrow()
  })

  it('accepts actions only', () => {
    expect(() =>
      PatchTaskRequestSchema.parse({
        actions: [
          {
            id: 'send',
            label: 'Send Reply',
            type: 'primary',
            target: { resourceType: 'workflow', resourceId: 'inb-01-send-subsequent-reply-workflow' }
          }
        ]
      })
    ).not.toThrow()
  })

  it('accepts both context and actions together', () => {
    expect(() =>
      PatchTaskRequestSchema.parse({
        context: { lead: { senderName: 'Amy' } },
        actions: [{ id: 'send', label: 'Send', type: 'primary' }]
      })
    ).not.toThrow()
  })

  it('accepts context alongside existing fields', () => {
    expect(() =>
      PatchTaskRequestSchema.parse({
        description: 'Updated description',
        priority: 7,
        context: { lead: { senderName: 'Amy' } }
      })
    ).not.toThrow()
  })

  it('rejects empty object — at least one field required', () => {
    expect(() => PatchTaskRequestSchema.parse({})).toThrow()
  })

  it('accepts empty actions array (no schema-level minimum)', () => {
    // actions: [] is technically valid schema-wise; business logic enforces content
    expect(() => PatchTaskRequestSchema.parse({ actions: [] })).not.toThrow()
  })

  it('rejects non-object context', () => {
    expect(() => PatchTaskRequestSchema.parse({ context: 'flat-string' })).toThrow()
  })
})

describe('SubmitActionParamsSchema', () => {
  it('validates valid submit action params', () => {
    const params = {
      actionId: 'approve',
      payload: { notes: 'Looks good' },
      notes: 'Approved by manager',
      userId: 'user-123'
    }

    expect(() => SubmitActionParamsSchema.parse(params)).not.toThrow()
  })

  it('validates with minimal params', () => {
    const params = {
      actionId: 'approve',
      userId: 'user-123'
    }

    expect(() => SubmitActionParamsSchema.parse(params)).not.toThrow()
  })

  it('rejects with empty action id', () => {
    const params = {
      actionId: '',
      userId: 'user-123'
    }

    expect(() => SubmitActionParamsSchema.parse(params)).toThrow()
  })

  it('rejects with empty user id', () => {
    const params = {
      actionId: 'approve',
      userId: ''
    }

    expect(() => SubmitActionParamsSchema.parse(params)).toThrow()
  })
})

describe('Validation helper functions', () => {
  describe('validateActions', () => {
    it('validates valid actions array', () => {
      const actions = [
        { id: 'approve', label: 'Approve', type: 'primary' as const },
        { id: 'reject', label: 'Reject', type: 'danger' as const }
      ]

      expect(() => validateActions(actions)).not.toThrow()
    })

    it('rejects empty array', () => {
      expect(() => validateActions([])).toThrow()
    })

    it('rejects array with too many actions', () => {
      const actions = Array.from({ length: 21 }, (_, i) => ({
        id: `action-${i}`,
        label: `Action ${i}`,
        type: 'primary' as const
      }))

      expect(() => validateActions(actions)).toThrow()
    })
  })

  describe('validateActionConfig', () => {
    it('validates valid action', () => {
      const action = {
        id: 'approve',
        label: 'Approve',
        type: 'primary' as const
      }

      expect(() => validateActionConfig(action)).not.toThrow()
    })

    it('rejects invalid action', () => {
      const action = {
        id: '',
        label: 'Approve',
        type: 'primary'
      }

      expect(() => validateActionConfig(action)).toThrow()
    })
  })

  describe('validateFormSchema', () => {
    it('validates valid form schema', () => {
      const schema = {
        fields: [{ name: 'field', label: 'Field', type: 'text' as const }]
      }

      expect(() => validateFormSchema(schema)).not.toThrow()
    })

    it('rejects invalid form schema', () => {
      const schema = {
        fields: []
      }

      expect(() => validateFormSchema(schema)).toThrow()
    })
  })

  describe('validateFormField', () => {
    it('validates valid field', () => {
      const field = {
        name: 'email',
        label: 'Email',
        type: 'text' as const
      }

      expect(() => validateFormField(field)).not.toThrow()
    })

    it('rejects invalid field', () => {
      const field = {
        name: '',
        label: 'Email',
        type: 'text'
      }

      expect(() => validateFormField(field)).toThrow()
    })
  })
})
