import { z } from 'zod';
import { isAllowedAuthorityHost, isAllowedGraphHost } from '../data/graphHosts.js';

export const loginSchema = z.object({
  email: z.string().email(),
  password: z.string().min(1)
});

export const profileSchema = z.object({
  email: z.string().email().optional(),
  displayName: z.string().min(1).max(120),
  jobTitle: z.string().max(120).optional().default(''),
  phone: z.string().max(60).optional().default(''),
  timezone: z.string().max(80).optional().default(''),
  avatarUrl: z.string().url().or(z.literal('')).optional().default('')
});

export const themeSchema = z.object({
  theme: z.string().min(1).max(48).regex(/^[a-z0-9_-]+$/)
});

export const passwordChangeSchema = z.object({
  currentPassword: z.string().optional().default(''),
  newPassword: z.string().optional().default('')
});

export const visibilitySchema = z.enum(['personal', 'shared', 'group']);

export const userSchema = z.object({
  email: z.string().email(),
  displayName: z.string().min(1),
  password: z.string().min(8).optional(),
  role: z.enum(['admin', 'user']).default('user'),
  groupIds: z.array(z.string()).default([])
});

export const groupSchema = z.object({
  name: z.string().min(1),
  description: z.string().optional(),
  userIds: z.array(z.string()).default([])
});

export const credentialSchema = z.object({
  name: z.string().min(1),
  kind: z.enum(['username_password', 'api_key']),
  username: z.string().optional(),
  secret: z.string().min(1),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const hostSchema = z.object({
  name: z.string().min(1),
  fqdn: z.string().optional(),
  address: z.string().min(1),
  osFamily: z.string().default('windows'),
  transport: z.enum(['winrm', 'ssh', 'local', 'api']).default('winrm'),
  port: z.number().int().nullable().optional(),
  credentialId: z.string().nullable().optional(),
  tags: z.array(z.string()).default([]),
  notes: z.string().optional(),
  visibility: visibilitySchema.default('shared'),
  groupId: z.string().nullable().optional()
});

const vcenterFilterSchema = z.object({
  field: z.enum(['name', 'hostname', 'fqdn', 'ip']).optional().default('hostname'),
  operator: z.enum(['contains', 'equals', 'startsWith', 'endsWith']).optional().default('contains'),
  value: z.string().max(200).optional().default('')
});

export const vcenterPreviewSchema = z.object({
  filter: vcenterFilterSchema.optional().default({}),
  limit: z.coerce.number().int().min(1).max(500).optional().default(100)
});

export const vcenterImportSchema = vcenterPreviewSchema.extend({
  vmIds: z.array(z.string().min(1)).optional().default([]),
  credentialId: z.string().nullable().optional(),
  visibility: visibilitySchema.default('shared'),
  groupId: z.string().nullable().optional(),
  transport: z.enum(['winrm', 'ssh', 'local', 'api']).default('winrm'),
  port: z.coerce.number().int().min(1).max(65535).nullable().optional(),
  tags: z.array(z.string().max(80)).optional().default([])
});

export const folderSchema = z.object({
  parentId: z.string().nullable().optional(),
  name: z.string().min(1),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const assetFolderSchema = z.object({
  parentId: z.string().nullable().optional(),
  name: z.string().min(1).max(180),
  description: z.string().max(600).optional().default(''),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const assetUploadSchema = z.object({
  folderId: z.string().nullable().optional(),
  name: z.string().min(1).max(220),
  originalName: z.string().min(1).max(260).optional(),
  description: z.string().max(1200).optional().default(''),
  mimeType: z.string().max(160).optional(),
  packagePath: z.string().max(500).optional().default(''),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const assetUpdateSchema = z.object({
  folderId: z.string().nullable().optional(),
  name: z.string().min(1).max(220).optional(),
  description: z.string().max(1200).optional(),
  packagePath: z.string().max(500).optional(),
  visibility: visibilitySchema.optional(),
  groupId: z.string().nullable().optional()
});

export const assetLinkSchema = z.object({
  targetType: z.enum(['script', 'runplan', 'psadt_profile', 'intune_deployment']).default('script'),
  targetId: z.string().min(1),
  linkRole: z.enum(['reference', 'package-file', 'installer', 'support-file', 'icon', 'detection-script']).default('reference'),
  packagePath: z.string().max(500).optional().default('')
});

export const variableNameSchema = z.string().min(1).max(80).regex(/^[A-Za-z_][A-Za-z0-9_]*$/);

export const customVariableSchema = z.object({
  name: variableNameSchema,
  description: z.string().max(500).optional().default(''),
  category: z.string().min(1).max(80).optional().default('Custom'),
  value: z.string().optional().default(''),
  valueType: z.enum(['string', 'number', 'boolean', 'json']).default('string'),
  sensitive: z.boolean().or(z.number()).optional().default(false),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const psadtProfileSchema = z.object({
  name: z.string().min(1).max(160),
  appVendor: z.string().max(120).optional().default(''),
  appName: z.string().max(160).optional().default(''),
  appVersion: z.string().max(80).optional().default(''),
  appArch: z.enum(['x64', 'x86', 'neutral']).optional().default('x64'),
  appLang: z.string().max(40).optional().default('EN'),
  appRevision: z.string().max(40).optional().default('01'),
  toolkitVersion: z.enum(['v4', 'v3-compatible']).optional().default('v4'),
  templateVersion: z.enum(['v4', 'v3']).optional().default('v4'),
  deploymentType: z.enum(['Install', 'Uninstall', 'Repair']).optional().default('Install'),
  deployMode: z.enum(['Auto', 'Interactive', 'Silent', 'NonInteractive']).optional().default('Auto'),
  requireAdmin: z.boolean().or(z.number()).optional().default(true),
  zeroConfig: z.boolean().or(z.number()).optional().default(false),
  suppressReboot: z.boolean().or(z.number()).optional().default(false),
  closeProcesses: z.array(z.object({
    name: z.string().min(1),
    description: z.string().optional().default('')
  })).optional().default([]),
  installTasks: z.array(z.object({
    type: z.enum(['exe', 'msi', 'msp', 'script']).default('exe'),
    phase: z.enum(['Pre-Install', 'Install', 'Post-Install', 'Pre-Uninstall', 'Uninstall', 'Post-Uninstall', 'Pre-Repair', 'Repair', 'Post-Repair']).default('Install'),
    filePath: z.string().min(1),
    arguments: z.string().optional().default(''),
    secureArguments: z.boolean().or(z.number()).optional().default(false)
  })).optional().default([]),
  uiPlan: z.record(z.string(), z.any()).optional().default({}),
  configPlan: z.record(z.string(), z.any()).optional().default({}),
  admxPlan: z.record(z.string(), z.any()).optional().default({}),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const psadtValidationSchema = z.object({
  content: z.string().optional().default(''),
  scriptId: z.string().optional(),
  profileId: z.string().optional(),
  platform: z.enum(['intune', 'configmgr', 'gpo', 'manual']).optional().default('intune')
});

export const psadtMigrationSchema = z.object({
  content: z.string().optional().default(''),
  scriptId: z.string().optional(),
  targetVersion: z.string().optional().default('4.2.0'),
  createScript: z.boolean().or(z.number()).optional().default(false),
  nameSuffix: z.string().max(80).optional().default('PSADT 4.2 migrated')
});

export const intuneDeploymentSchema = z.object({
  name: z.string().min(1).max(160),
  profileId: z.string().nullable().optional(),
  scriptId: z.string().nullable().optional(),
  applicationId: z.string().nullable().optional(),
  sourceFolder: z.string().max(500).optional().default(''),
  intunewinFile: z.string().max(500).optional().default(''),
  appType: z.string().min(1).max(80).optional().default('Windows app (Win32)'),
  commandStyle: z.enum(['v4', 'legacy-v3']).optional().default('v4'),
  installBehavior: z.enum(['system', 'user']).optional().default('system'),
  restartBehavior: z.enum(['return-code', 'suppress', 'intune']).optional().default('return-code'),
  uiMode: z.enum(['native-v4', 'serviceui-legacy', 'silent']).optional().default('native-v4'),
  requirements: z.object({
    architecture: z.enum(['x64', 'x86', 'both']).optional().default('x64'),
    minOs: z.string().max(80).optional().default('Windows 10 22H2'),
    diskSpaceMb: z.number().or(z.string()).optional().default(0),
    runAs32Bit: z.boolean().or(z.number()).optional().default(false)
  }).optional().default({}),
  installCommand: z.string().max(500).optional().default(''),
  uninstallCommand: z.string().max(500).optional().default(''),
  detectionType: z.enum(['msi-product-code', 'file-version', 'registry', 'custom-script']).optional().default('custom-script'),
  detectionRule: z.string().max(3000).optional().default(''),
  returnCodes: z.array(z.object({
    code: z.string().or(z.number()),
    type: z.string().min(1).max(40),
    meaning: z.string().max(240).optional().default('')
  })).optional().default([]),
  assignments: z.array(z.object({
    ring: z.string().min(1).max(80),
    intent: z.enum(['available', 'required', 'uninstall', 'exclude']).optional().default('required'),
    groupName: z.string().max(160).optional().default(''),
    groupId: z.string().max(120).optional().default(''),
    groupMode: z.enum(['group', 'allDevices', 'allUsers']).optional().default('group'),
    filterId: z.string().max(120).optional().default(''),
    filterType: z.enum(['none', 'include', 'exclude']).optional().default('none'),
    autoUpdate: z.boolean().or(z.number()).optional().default(false),
    notes: z.string().max(240).optional().default('')
  })).optional().default([]),
  relationships: z.array(z.object({
    kind: z.enum(['supersedence', 'dependency']).default('supersedence'),
    targetAppId: z.string().min(1).max(160),
    targetName: z.string().max(200).optional().default(''),
    mode: z.string().max(40).optional().default('')
  })).optional().default([]),
  status: z.enum(['draft', 'ready', 'published', 'retired']).optional().default('draft'),
  autoPromoteAfterHours: z.number().int().min(0).or(z.string()).optional().default(0),
  autoPromoteRing: z.string().max(80).optional().default(''),
  autoPromoteIntent: z.enum(['available', 'required', 'uninstall', 'exclude']).optional().default('required'),
  graphAppId: z.string().max(160).optional().default(''),
  graphConnectionId: z.string().nullable().optional(),
  notes: z.string().max(1000).optional().default(''),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const applicationSchema = z.object({
  name: z.string().min(1).max(160),
  vendor: z.string().max(120).optional().default(''),
  publisher: z.string().max(160).optional().default(''),
  currentVersion: z.string().max(80).optional().default(''),
  latestKnownVersion: z.string().max(80).optional().default(''),
  versionSource: z.enum(['manual', 'url', 'winget']).optional().default('manual'),
  versionSourceRef: z.string().max(500).optional().default(''),
  graphConnectionId: z.string().nullable().optional(),
  currentGraphAppId: z.string().max(160).optional().default(''),
  autoCheck: z.boolean().or(z.number()).optional().default(false),
  notes: z.string().max(1000).optional().default(''),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const applicationImportSchema = z.object({
  connectionId: z.string().min(1),
  graphAppId: z.string().min(1).max(160),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const graphConnectionSchema = z.object({
  name: z.string().min(1).max(160),
  tenantId: z.string().min(1).max(120),
  clientId: z.string().min(1).max(120),
  clientSecret: z.string().optional().default(''),
  cloud: z.enum(['global', 'gcc', 'gcchigh', 'dod', 'china', 'custom']).optional().default('global'),
  graphBaseUrl: z.string().url().refine(isAllowedGraphHost, {
    message: 'graphBaseUrl must be a recognized Microsoft Graph host'
  }).optional().default('https://graph.microsoft.com'),
  authorityHost: z.string().url().refine(isAllowedAuthorityHost, {
    message: 'authorityHost must be a recognized Microsoft login host'
  }).optional().default('https://login.microsoftonline.com'),
  defaultApiVersion: z.enum(['v1.0', 'beta']).optional().default('v1.0'),
  enabled: z.boolean().or(z.number()).optional().default(true),
  allowWrite: z.boolean().or(z.number()).optional().default(false),
  requireApproval: z.boolean().or(z.number()).optional().default(false),
  publisherIds: z.array(z.string()).optional().default([]),
  approverIds: z.array(z.string()).optional().default([]),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional()
});

export const graphDeploymentLinkSchema = z.object({
  connectionId: z.string().optional().default(''),
  graphAppId: z.string().min(1).max(160)
});

export const graphDeploymentSyncSchema = z.object({
  connectionId: z.string().optional().default(''),
  graphAppId: z.string().optional().default(''),
  mode: z.enum(['reports', 'legacy-status', 'both']).optional().default('reports')
});

const scriptPayloadSchema = z.object({
  folderId: z.string().nullable().optional(),
  folder_id: z.string().nullable().optional(),
  name: z.string().min(1),
  description: z.string().optional().default(''),
  content: z.string().default(''),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional(),
  group_id: z.string().nullable().optional()
});

export const scriptTestRunSchema = z.object({
  hostId: z.string().min(1),
  credentialId: z.string().min(1)
});

const runPlanPayloadSchema = z.object({
  name: z.string().min(1),
  description: z.string().optional().default(''),
  scriptId: z.string().optional(),
  script_id: z.string().optional(),
  visibility: visibilitySchema.default('personal'),
  groupId: z.string().nullable().optional(),
  group_id: z.string().nullable().optional(),
  parallel: z.boolean().or(z.number()).default(true),
  hostIds: z.array(z.string()).optional()
});

export function normalizeScriptPayload(body) {
  const parsed = scriptPayloadSchema.parse(body);
  return {
    folderId: parsed.folderId ?? parsed.folder_id ?? null,
    name: parsed.name,
    description: parsed.description || '',
    content: parsed.content || '',
    visibility: parsed.visibility,
    groupId: parsed.visibility === 'group' ? parsed.groupId ?? parsed.group_id ?? null : null
  };
}

export function normalizeRunPlanPayload(body) {
  const parsed = runPlanPayloadSchema.parse(body);
  return {
    name: parsed.name,
    description: parsed.description || '',
    scriptId: parsed.scriptId || parsed.script_id,
    visibility: parsed.visibility,
    groupId: parsed.visibility === 'group' ? parsed.groupId ?? parsed.group_id ?? null : null,
    parallel: Boolean(parsed.parallel),
    hostIds: parsed.hostIds || []
  };
}
