import { z } from 'zod'
import { inlineFileRefQuerySchema } from '@/lib/api/contracts/primitives'
import { shareRecordSchema } from '@/lib/api/contracts/public-shares'
import { defineRouteContract } from '@/lib/api/contracts/types'

export const workspaceFileScopeSchema = z.enum(['active', 'archived', 'all'])

export const workspaceFilesParamsSchema = z.object({
  id: z.string({ error: 'Workspace ID is required' }).min(1, 'Workspace ID is required'),
})

export const workspaceFileParamsSchema = workspaceFilesParamsSchema.extend({
  fileId: z.string({ error: 'File ID is required' }).min(1, 'File ID is required'),
})

export const listWorkspaceFilesQuerySchema = z.object({
  scope: workspaceFileScopeSchema.default('active'),
})

/**
 * Binary stream of an image embedded in a workspace markdown document, scoped to the
 * workspace in the path. The route serves the bytes only when the referenced file is a
 * `workspace` file belonging to `[id]` — cross-workspace references do not resolve.
 */
export const getInlineWorkspaceFileContract = defineRouteContract({
  method: 'GET',
  path: '/api/workspaces/[id]/files/inline',
  params: workspaceFilesParamsSchema,
  query: inlineFileRefQuerySchema,
  response: {
    mode: 'binary',
  },
})

const workspaceFileNameSchema = z
  .string({ error: 'Name is required' })
  .trim()
  .min(1, 'Name is required')
  .refine(
    (name) => name !== '.' && name !== '..' && !name.includes('/') && !name.includes('\\'),
    'Name cannot contain path separators or dot segments'
  )

export const renameWorkspaceFileBodySchema = z.object({
  name: workspaceFileNameSchema,
})

export const updateWorkspaceFileContentBodySchema = z.object({
  content: z.string(),
  encoding: z.enum(['base64', 'utf-8']).optional(),
})

export const workspaceFileRecordSchema = z.object({
  id: z.string(),
  workspaceId: z.string(),
  name: z.string(),
  key: z.string(),
  path: z.string(),
  url: z.string().optional(),
  size: z.number(),
  type: z.string(),
  uploadedBy: z.string(),
  folderId: z.string().nullable(),
  folderPath: z.string().nullable().optional(),
  deletedAt: z.coerce.date().nullable().optional(),
  uploadedAt: z.coerce.date(),
  updatedAt: z.coerce.date(),
  storageContext: z.enum(['workspace', 'mothership']).optional(),
  share: shareRecordSchema.nullable().optional(),
})

const workspaceFileSuccessSchema = z.object({
  success: z.boolean(),
})

const listWorkspaceFilesResponseSchema = workspaceFileSuccessSchema.extend({
  files: z.array(workspaceFileRecordSchema),
})

export type ListWorkspaceFilesResponse = z.output<typeof listWorkspaceFilesResponseSchema>

export const listWorkspaceFilesContract = defineRouteContract({
  method: 'GET',
  path: '/api/workspaces/[id]/files',
  params: workspaceFilesParamsSchema,
  query: listWorkspaceFilesQuerySchema,
  response: {
    mode: 'json',
    schema: listWorkspaceFilesResponseSchema,
  },
})

export const renameWorkspaceFileContract = defineRouteContract({
  method: 'PATCH',
  path: '/api/workspaces/[id]/files/[fileId]',
  params: workspaceFileParamsSchema,
  body: renameWorkspaceFileBodySchema,
  response: {
    mode: 'json',
    schema: workspaceFileSuccessSchema.extend({
      file: workspaceFileRecordSchema,
    }),
  },
})

export const deleteWorkspaceFileContract = defineRouteContract({
  method: 'DELETE',
  path: '/api/workspaces/[id]/files/[fileId]',
  params: workspaceFileParamsSchema,
  response: {
    mode: 'json',
    schema: workspaceFileSuccessSchema,
  },
})

export const restoreWorkspaceFileContract = defineRouteContract({
  method: 'POST',
  path: '/api/workspaces/[id]/files/[fileId]/restore',
  params: workspaceFileParamsSchema,
  response: {
    mode: 'json',
    schema: workspaceFileSuccessSchema,
  },
})

export const updateWorkspaceFileContentContract = defineRouteContract({
  method: 'PUT',
  path: '/api/workspaces/[id]/files/[fileId]/content',
  params: workspaceFileParamsSchema,
  body: updateWorkspaceFileContentBodySchema,
  response: {
    mode: 'json',
    schema: workspaceFileSuccessSchema.extend({
      file: workspaceFileRecordSchema,
    }),
  },
})

const documentStyleSummarySchema = z
  .object({
    format: z.enum(['docx', 'pptx', 'pdf']),
    // OOXML theme — present for pptx, present for docx when theme1.xml exists, absent for pdf
    theme: z
      .object({
        colors: z.record(z.string(), z.string()),
        fonts: z.object({ major: z.string(), minor: z.string() }),
      })
      .optional(),
    // docx only
    styles: z.array(z.object({}).passthrough()).optional(),
    defaults: z.object({ fontSize: z.number().optional(), font: z.string().optional() }).optional(),
    // pdf only
    pageSize: z
      .object({
        preset: z.enum(['A4', 'letter', 'custom']),
        widthPt: z.number().optional(),
        heightPt: z.number().optional(),
      })
      .optional(),
    fonts: z.array(z.string()).optional(),
    // pptx only
    slideCount: z.number().optional(),
    aspectRatio: z.enum(['16:9', '4:3', 'custom']).optional(),
    background: z.string().optional(),
  })
  .passthrough()

export const workspaceFileStyleContract = defineRouteContract({
  method: 'GET',
  path: '/api/workspaces/[id]/files/[fileId]/style',
  params: workspaceFileParamsSchema,
  response: {
    mode: 'json',
    schema: documentStyleSummarySchema,
  },
})

const compiledCheckResponseSchema = z.union([
  z.object({ ok: z.literal(true) }),
  z.object({ ok: z.literal(false), error: z.string(), errorName: z.string() }),
])

export const workspaceFileCompiledCheckContract = defineRouteContract({
  method: 'GET',
  path: '/api/workspaces/[id]/files/[fileId]/compiled-check',
  params: workspaceFileParamsSchema,
  response: {
    mode: 'json',
    schema: compiledCheckResponseSchema,
  },
})

export const workspacePresignedUploadBodySchema = z.object({
  fileName: workspaceFileNameSchema,
  contentType: z.string().min(1, 'contentType is required'),
  fileSize: z.number().nonnegative('fileSize must be a non-negative number'),
  folderId: z.string().nullable().optional(),
})

export type WorkspacePresignedUploadBody = z.input<typeof workspacePresignedUploadBodySchema>

const workspacePresignedFileInfoSchema = z.object({
  path: z.string(),
  key: z.string(),
  name: z.string(),
  size: z.number(),
  type: z.string(),
})

const workspacePresignedUploadResponseSchema = z.object({
  fileName: z.string(),
  presignedUrl: z.string(),
  fileInfo: workspacePresignedFileInfoSchema,
  uploadHeaders: z.record(z.string(), z.string()).optional(),
  directUploadSupported: z.boolean(),
})

export const workspacePresignedUploadContract = defineRouteContract({
  method: 'POST',
  path: '/api/workspaces/[id]/files/presigned',
  params: workspaceFilesParamsSchema,
  body: workspacePresignedUploadBodySchema,
  response: {
    mode: 'json',
    schema: workspacePresignedUploadResponseSchema,
  },
})

export const registerWorkspaceFileBodySchema = z.object({
  key: z.string().min(1, 'key is required'),
  name: workspaceFileNameSchema,
  contentType: z.string().min(1, 'contentType is required'),
  folderId: z.string().nullable().optional(),
})

export type RegisterWorkspaceFileBody = z.input<typeof registerWorkspaceFileBodySchema>

const registeredWorkspaceFileSchema = z.object({
  id: z.string(),
  name: z.string(),
  url: z.string(),
  size: z.number(),
  type: z.string(),
  key: z.string(),
  context: z.string().optional(),
})

const registerWorkspaceFileResponseSchema = z.object({
  success: z.boolean(),
  file: registeredWorkspaceFileSchema.optional(),
  error: z.string().optional(),
  isDuplicate: z.boolean().optional(),
})

export type RegisterWorkspaceFileResponse = z.output<typeof registerWorkspaceFileResponseSchema>

export const registerWorkspaceFileContract = defineRouteContract({
  method: 'POST',
  path: '/api/workspaces/[id]/files/register',
  params: workspaceFilesParamsSchema,
  body: registerWorkspaceFileBodySchema,
  response: {
    mode: 'json',
    schema: registerWorkspaceFileResponseSchema,
  },
})
