import { z } from 'zod'
import { UuidSchema, CredentialNameSchema } from '../../platform/utils/validation'

/**
 * Credential API Validation Schemas
 *
 * Separate from credential configuration schemas (schemas.ts).
 * - schemas.ts: Credential field definitions and type registry
 * - api-schemas.ts: HTTP request/response validation
 *
 * Design: Input Validation Standardization
 * @see apps/docs/content/docs/in-progress/active-development/security/active/credentials-integrations-validation-implementation.mdx
 */

/**
 * Credential type validation
 * These are the actual `type` values stored in the database:
 * - 'oauth': All OAuth providers (notion, google-sheets) store this type
 * - 'api-key': Generic single-field API key credentials
 * - 'webhook-secret': Webhook signing secrets for signature validation
 * - 'api-key-secret': API key and secret pair credentials
 * - 'clickup': ClickUp personal-token credentials with provider-specific schema/verification
 *
 * Note: Provider-specific identifiers (notion, google-sheets) are CREDENTIAL_SCHEMAS
 * keys used for UI lookup, NOT stored type values. OAuth credentials store type='oauth'.
 */
export const CredentialTypeSchema = z.enum(['oauth', 'api-key', 'webhook-secret', 'api-key-secret', 'clickup'])

/**
 * Credential value validation
 * - Must be a non-empty object
 * - Keys are strings, values can be any JSON type
 * - Max 50 keys (prevents DoS)
 * - Individual string values max 10KB (prevents DoS)
 *
 * SECURITY:
 * - Prevents DoS via massive credential payloads
 * - Enforces reasonable limits for credential storage
 */
const CredentialValueSchema = z
  .record(z.string(), z.unknown())
  .refine((val) => Object.keys(val).length > 0, { message: 'Credential value must not be empty' })
  .refine((val) => Object.keys(val).length <= 50, { message: 'Credential value has too many keys (max 50)' })
  .refine(
    (val) => {
      // Check individual string values for size
      for (const v of Object.values(val)) {
        if (typeof v === 'string' && v.length > 10240) {
          return false
        }
      }
      return true
    },
    { message: 'Individual credential values too large (max 10KB per string)' }
  )

/**
 * POST /api/credentials - Create credential
 */
export const CreateCredentialRequestSchema = z
  .object({
    name: CredentialNameSchema,
    type: CredentialTypeSchema,
    value: CredentialValueSchema,
    provider: z.string().optional() // OAuth provider ID ('dropbox', 'notion', 'google-sheets')
  })
  .strict() // Reject unknown fields (prevents mass assignment)

/**
 * Response for credential creation
 */
export const CreateCredentialResponseSchema = z.object({
  id: UuidSchema,
  name: z.string()
})

/**
 * GET /api/credentials - List credentials
 */
export const ListCredentialsResponseSchema = z.object({
  credentials: z.array(
    z.object({
      id: UuidSchema,
      name: z.string(),
      type: z.string(),
      provider: z.string().nullable(), // OAuth provider or null for non-OAuth
      createdAt: z.string().datetime()
    })
  )
})

/** API response type for a single credential list item */
export type CredentialListItem = z.infer<typeof ListCredentialsResponseSchema>['credentials'][number]

/**
 * PATCH /api/credentials/:credentialId - Update credential
 */
export const UpdateCredentialParamsSchema = z.object({
  credentialId: UuidSchema
})

export const UpdateCredentialRequestSchema = z
  .object({
    value: CredentialValueSchema.optional(),
    name: CredentialNameSchema.optional()
  })
  .strict()
  .refine((data) => data.value !== undefined || data.name !== undefined, {
    message: 'At least one field (value or name) must be provided'
  })

/**
 * DELETE /api/credentials/:credentialId - Delete credential
 */
export const DeleteCredentialParamsSchema = z.object({
  credentialId: UuidSchema
})

/**
 * POST /api/credentials/:credentialId/verify - Verify credential with provider smoke check
 */
export const VerifyCredentialParamsSchema = z.object({
  credentialId: UuidSchema
})

export const VerifyCredentialResponseSchema = z.object({
  ok: z.boolean(),
  provider: z.string(),
  checkedAt: z.string().datetime(),
  message: z.string().optional(),
  details: z.record(z.string(), z.unknown()).optional()
})

/**
 * Export all schemas for use in routes
 */
export const CredentialSchemas = {
  CreateRequest: CreateCredentialRequestSchema,
  CreateResponse: CreateCredentialResponseSchema,
  ListResponse: ListCredentialsResponseSchema,
  UpdateParams: UpdateCredentialParamsSchema,
  UpdateRequest: UpdateCredentialRequestSchema,
  DeleteParams: DeleteCredentialParamsSchema,
  VerifyParams: VerifyCredentialParamsSchema,
  VerifyResponse: VerifyCredentialResponseSchema
}
