import { z } from 'zod';
import { Base64Schema, CursorSchema, PathSchema, Sha256HexSchema } from './primitives.js';
import { FileEntrySchema, FileKindSchema, ListPageSchema } from './file-entry.js';

// ─── list ────────────────────────────────────────────────────

export const ListArgsSchema = z.object({
  path: PathSchema,
  cursor: CursorSchema.optional(),
  pageSize: z.number().int().min(1).max(1000).default(100),
  filter: z
    .object({
      prefix: z.string().max(256).optional(),
      kind: FileKindSchema.optional(),
    })
    .optional(),
});
export type ListArgs = z.infer<typeof ListArgsSchema>;
export const ListResultSchema = ListPageSchema;
export type ListResult = z.infer<typeof ListResultSchema>;

// ─── stat ────────────────────────────────────────────────────

export const StatArgsSchema = z.object({ path: PathSchema });
export type StatArgs = z.infer<typeof StatArgsSchema>;
export const StatResultSchema = FileEntrySchema;
export type StatResult = z.infer<typeof StatResultSchema>;

// ─── mkdir ───────────────────────────────────────────────────

export const MkdirArgsSchema = z.object({
  path: PathSchema,
  recursive: z.boolean().default(false),
});
export type MkdirArgs = z.infer<typeof MkdirArgsSchema>;
export const MkdirResultSchema = z.object({ entry: FileEntrySchema });
export type MkdirResult = z.infer<typeof MkdirResultSchema>;

// ─── delete ──────────────────────────────────────────────────

export const DeleteArgsSchema = z.object({
  path: PathSchema,
  recursive: z.boolean().default(false),
});
export type DeleteArgs = z.infer<typeof DeleteArgsSchema>;
export const DeleteResultSchema = z.object({
  deletedCount: z.number().int().nonnegative(),
});
export type DeleteResult = z.infer<typeof DeleteResultSchema>;

// ─── move ────────────────────────────────────────────────────

export const MoveArgsSchema = z.object({
  src: PathSchema,
  dst: PathSchema,
  overwrite: z.boolean().default(false),
});
export type MoveArgs = z.infer<typeof MoveArgsSchema>;
export const MoveResultSchema = z.object({ entry: FileEntrySchema });
export type MoveResult = z.infer<typeof MoveResultSchema>;

// ─── read ────────────────────────────────────────────────────

export const ReadArgsSchema = z.object({
  path: PathSchema,
  range: z
    .object({
      start: z.number().int().nonnegative(),
      end: z.number().int().positive(),
    })
    .optional(),
  /** Force inline path even if size unknown / large. Use with care. */
  preferInline: z.boolean().optional(),
});
export type ReadArgs = z.infer<typeof ReadArgsSchema>;

export const ReadResultSchema = z.discriminatedUnion('kind', [
  z.object({
    kind: z.literal('inline'),
    bytesB64: Base64Schema,
    size: z.number().int().nonnegative(),
    sha256: Sha256HexSchema,
    contentType: z.string().optional(),
  }),
  z.object({
    kind: z.literal('streams'),
    streamId: z.string(),
    size: z.number().int().nonnegative(),
    sha256: Sha256HexSchema,
    contentType: z.string().optional(),
  }),
]);
export type ReadResult = z.infer<typeof ReadResultSchema>;

// ─── write ───────────────────────────────────────────────────

export const WriteArgsSchema = z.discriminatedUnion('kind', [
  z.object({
    kind: z.literal('inline'),
    path: PathSchema,
    bytesB64: Base64Schema,
    contentType: z.string().optional(),
    overwrite: z.boolean().default(false),
  }),
  z.object({
    kind: z.literal('streams'),
    path: PathSchema,
    /** Declared plaintext size; server clamps quota against this. */
    size: z.number().int().nonnegative(),
    contentType: z.string().optional(),
    overwrite: z.boolean().default(false),
    /** base64url(16) — matches `metadata.shadeFilesWriteId` on the streams transfer. */
    writeId: z.string(),
  }),
]);
export type WriteArgs = z.infer<typeof WriteArgsSchema>;
export const WriteResultSchema = z.object({ entry: FileEntrySchema });
export type WriteResult = z.infer<typeof WriteResultSchema>;

// ─── getThumbnail ────────────────────────────────────────────

export const ThumbnailSizeSchema = z.union([
  z.literal(64),
  z.literal(128),
  z.literal(256),
  z.literal(512),
]);
export type ThumbnailSize = z.infer<typeof ThumbnailSizeSchema>;

export const GetThumbnailArgsSchema = z.object({
  path: PathSchema,
  size: ThumbnailSizeSchema,
  format: z.enum(['png', 'webp', 'jpeg']).default('png'),
});
export type GetThumbnailArgs = z.infer<typeof GetThumbnailArgsSchema>;

export const GetThumbnailResultSchema = z.object({
  bytesB64: Base64Schema,
  format: z.enum(['png', 'webp', 'jpeg']),
  width: z.number().int().positive().max(4096),
  height: z.number().int().positive().max(4096),
  sha256: Sha256HexSchema,
});
export type GetThumbnailResult = z.infer<typeof GetThumbnailResultSchema>;

// ─── custom ──────────────────────────────────────────────────

export const CustomArgsSchema = z.object({
  name: z.string().min(1).max(128).regex(/^[a-z0-9.-]+$/i, 'invalid custom op name'),
  payload: z.unknown(),
});
export type CustomArgs = z.infer<typeof CustomArgsSchema>;

export const CustomResultSchema = z.object({
  result: z.unknown(),
});
export type CustomResult = z.infer<typeof CustomResultSchema>;
