import { z } from 'zod'

export const shellDeviceSchema = z.enum(['desktop', 'mobile'])
export type ShellDevice = z.infer<typeof shellDeviceSchema>

const locationSchema = z.object({
  pathname: z.string().min(1).max(512),
  search: z.string().max(2048),
  hash: z.string().max(2048),
}).strict()

const rectSchema = z.object({
  x: z.number().finite().min(-100_000).max(100_000),
  y: z.number().finite().min(-100_000).max(100_000),
  w: z.number().finite().min(320).max(10_000),
  h: z.number().finite().min(220).max(10_000),
}).strict()

const windowSchema = z.object({
  instanceId: z.string().min(1).max(128),
  moduleId: z.string().min(1).max(128),
  location: locationSchema,
  rect: rectSchema,
  state: z.enum(['normal', 'minimized', 'maximized', 'snapped']),
  snapZone: z.enum(['left', 'right', 'tl', 'tr', 'bl', 'br']).optional(),
  preSnapRect: rectSchema.optional(),
}).strict()

const onboardingSchema = z.object({
  coachMarksCompleted: z.boolean().optional(),
}).strict()

export const desktopShellLayoutSchema = z.object({
  desktopIcons: z.array(z.object({ moduleId: z.string().min(1).max(128), cell: z.number().int().nonnegative().max(10_000) }).strict()).max(128),
  pinnedTaskbar: z.array(z.string().min(1).max(128)).max(128),
  widgets: z.array(z.object({
    id: z.string().min(1).max(128), moduleId: z.string().min(1).max(128),
    cell: z.number().int().nonnegative().max(10_000), size: z.enum(['s', 'm', 'l']),
  }).strict()).max(128),
  windows: z.array(windowSchema).max(12),
  onboarding: onboardingSchema.optional(),
}).strict()

export const mobileShellLayoutSchema = z.object({
  homeIcons: z.array(z.object({ moduleId: z.string().min(1).max(128), cell: z.number().int().nonnegative().max(10_000) }).strict()).max(128),
  dock: z.array(z.string().min(1).max(128)).max(4),
  widgets: z.array(z.object({
    widgetId: z.string().min(1).max(128), moduleId: z.string().min(1).max(128),
    cell: z.number().int().nonnegative().max(10_000),
  }).strict()).max(128),
  onboarding: onboardingSchema.optional(),
}).strict()

const envelopeFields = {
  v: z.literal(1),
  writer: z.string().min(1).max(128),
  committedAt: z.string().datetime(),
}

export const desktopShellLayoutEnvelopeSchema = z.object({ ...envelopeFields, data: desktopShellLayoutSchema }).strict()
export const mobileShellLayoutEnvelopeSchema = z.object({ ...envelopeFields, data: mobileShellLayoutSchema }).strict()
export const clientShellLayoutSchema = desktopShellLayoutSchema.partial().strict()
export const clientMobileShellLayoutSchema = mobileShellLayoutSchema.partial().strict()

export type ShellLayoutPayload = z.infer<typeof clientShellLayoutSchema>
export type MobileShellLayoutPayload = z.infer<typeof clientMobileShellLayoutSchema>
export type ShellLayoutEnvelope = z.infer<typeof desktopShellLayoutEnvelopeSchema> | z.infer<typeof mobileShellLayoutEnvelopeSchema>

export function parseShellLayoutPayload(value: unknown): ShellLayoutPayload | null {
  const parsed = clientShellLayoutSchema.safeParse(value)
  return parsed.success ? parsed.data : null
}

export function parseMobileShellLayoutPayload(value: unknown): MobileShellLayoutPayload | null {
  const parsed = clientMobileShellLayoutSchema.safeParse(value)
  return parsed.success ? parsed.data : null
}

export function parseShellLayoutEnvelope(value: unknown): ShellLayoutEnvelope | null {
  const parsed = z.union([desktopShellLayoutEnvelopeSchema, mobileShellLayoutEnvelopeSchema]).safeParse(value)
  return parsed.success ? parsed.data : null
}
