import { z } from "zod"

export const wgStatusSchema = z.enum(["up", "down"])

export const wgPeerDtoSchema = z.object({
  id: z.string().min(1),
  rosId: z.string().min(1),
  publicKey: z.string(),
  allowedIps: z.array(z.string()),
  endpoint: z.string().optional(),
  latestHandshake: z.string().optional(),
  transferRx: z.number().nonnegative().optional(),
  transferTx: z.number().nonnegative().optional(),
  persistentKeepalive: z.number().int().nonnegative().optional(),
  persistent: z.boolean().optional(),
  comment: z.string().optional(),
  disabled: z.boolean().optional(),
  name: z.string().optional(),
  clientAddress: z.string().optional(),
  clientDns: z.string().optional(),
  clientEndpoint: z.string().optional(),
})

export const wgIfaceDtoSchema = z.object({
  id: z.string().min(1),
  rosId: z.string().min(1),
  name: z.string().min(1),
  serverId: z.string().min(1),
  serverName: z.string(),
  serverCountry: z.string().optional(),
  listenPort: z.number().int().positive(),
  mtu: z.number().int().positive(),
  publicKey: z.string().optional(),
  privateKey: z.string().optional(),
  address: z.string().optional(),
  peers: z.array(wgPeerDtoSchema),
  comment: z.string(),
  enabled: z.boolean(),
  status: wgStatusSchema,
})

export const wgListResponseSchema = z.object({
  interfaces: z.array(wgIfaceDtoSchema),
  failures: z
    .array(
      z.object({
        serverId: z.string(),
        serverName: z.string().optional(),
        error: z.string(),
      }),
    )
    .optional(),
})

export const wgCreatePeerSchema = z.object({
  publicKey: z.string().min(1),
  allowedAddresses: z.array(z.string().min(1)).min(1),
  endpointAddress: z.string().optional(),
  endpointPort: z.number().int().positive().optional(),
  persistentKeepalive: z.number().int().nonnegative().optional(),
  comment: z.string().optional(),
  name: z.string().optional(),
  privateKey: z.enum(["auto", "none"]).or(z.string().min(1)).optional(),
  clientAddress: z.string().optional(),
  clientDns: z.string().optional(),
  clientEndpoint: z.string().optional(),
  disabled: z.boolean().optional(),
})

export const wgCreateInterfaceSchema = z.object({
  serverId: z.union([z.string(), z.number()]),
  name: z.string().min(1).max(64),
  listenPort: z.number().int().positive().default(13231),
  mtu: z.number().int().positive().default(1420),
  comment: z.string().optional(),
  privateKey: z.string().min(1).optional(),
  address: z.string().optional(),
  disabled: z.boolean().optional(),
  peer: wgCreatePeerSchema.optional(),
})

export const wgPatchInterfaceSchema = z.object({
  name: z.string().min(1).max(64).optional(),
  listenPort: z.number().int().positive().optional(),
  mtu: z.number().int().positive().optional(),
  comment: z.string().optional(),
  disabled: z.boolean().optional(),
  privateKey: z.string().min(1).optional(),
})

export const wgCreatePeerRequestSchema = wgCreatePeerSchema.extend({
  serverId: z.union([z.string(), z.number()]),
  interfaceName: z.string().min(1),
})

export const wgPatchPeerSchema = z.object({
  publicKey: z.string().min(1).optional(),
  allowedAddresses: z.array(z.string().min(1)).min(1).optional(),
  endpointAddress: z.string().optional(),
  endpointPort: z.number().int().positive().optional(),
  persistentKeepalive: z.number().int().nonnegative().optional(),
  comment: z.string().optional(),
  name: z.string().optional(),
  disabled: z.boolean().optional(),
  clientAddress: z.string().optional(),
  clientDns: z.string().optional(),
  clientEndpoint: z.string().optional(),
})

export const wgImportFormatSchema = z.enum(["auto", "rsc", "conf"])

export const wgImportRequestSchema = z.object({
  serverId: z.union([z.string(), z.number()]),
  content: z.string().min(1),
  format: wgImportFormatSchema.optional().default("auto"),
  dryRun: z.boolean().optional().default(false),
})

export const wgExportFormatSchema = z.enum(["rsc", "conf", "peer-conf"])

export const wgExportRequestSchema = z.object({
  serverId: z.union([z.string(), z.number()]),
  interfaceName: z.string().min(1),
  format: wgExportFormatSchema,
  peerId: z.string().optional(),
  includePrivateKey: z.boolean().optional().default(false),
})

export const wgImportPreviewSchema = z.object({
  format: z.enum(["rsc", "conf"]),
  interface: z.object({
    name: z.string(),
    listenPort: z.number().int().positive().optional(),
    mtu: z.number().int().positive().optional(),
    privateKey: z.string().optional(),
    comment: z.string().optional(),
    address: z.string().optional(),
    disabled: z.boolean().optional(),
  }),
  peers: z.array(wgCreatePeerSchema),
})

export const wgImportResponseSchema = z.object({
  dryRun: z.boolean(),
  preview: wgImportPreviewSchema,
  applied: z
    .object({
      interfaceName: z.string(),
      peersCreated: z.number().int().nonnegative(),
    })
    .optional(),
})

export const wgExportResponseSchema = z.object({
  format: wgExportFormatSchema,
  filename: z.string(),
  content: z.string(),
})

export type WgPeerDto = z.infer<typeof wgPeerDtoSchema>
export type WgIfaceDto = z.infer<typeof wgIfaceDtoSchema>
export type WgListResponse = z.infer<typeof wgListResponseSchema>
export type WgCreateInterface = z.infer<typeof wgCreateInterfaceSchema>
export type WgPatchInterface = z.infer<typeof wgPatchInterfaceSchema>
export type WgCreatePeerRequest = z.infer<typeof wgCreatePeerRequestSchema>
export type WgPatchPeer = z.infer<typeof wgPatchPeerSchema>
export type WgImportRequest = z.infer<typeof wgImportRequestSchema>
export type WgExportRequest = z.infer<typeof wgExportRequestSchema>
export type WgImportPreview = z.infer<typeof wgImportPreviewSchema>
export type WgImportResponse = z.infer<typeof wgImportResponseSchema>
export type WgExportResponse = z.infer<typeof wgExportResponseSchema>
