import { z } from 'zod';

import { baseListQuerySchema } from '@/lib/api/list-query';
import { VALID_MERGE_TOKENS, isCustomMergeToken } from '@/lib/templates/merge-fields';

// A token is acceptable if it's in the static catalog OR matches the
// dynamic `{{custom.<fieldName>}}` shape. The resolver checks the actual
// per-port custom-field definition at expand time and substitutes the
// stored value (or leaves the token unresolved if no definition matches).
function isAcceptableMergeToken(token: string): boolean {
  return VALID_MERGE_TOKENS.has(token) || isCustomMergeToken(token);
}

const mergeFieldsSchema = z
  .array(z.string())
  .optional()
  .default([])
  .refine((tokens) => tokens.every(isAcceptableMergeToken), {
    error: (issue) => {
      const tokens = issue.input as string[] | undefined;
      const unknown = tokens?.filter((t) => !isAcceptableMergeToken(t)) ?? [];
      return `Unknown merge tokens: ${unknown.join(', ')}`;
    },
  });

export const templateFormats = ['html', 'pdf_form', 'pdf_overlay', 'documenso_render'] as const;

const createTemplateBaseSchema = z.object({
  name: z.string().min(1).max(200),
  description: z.string().max(500).optional(),
  templateType: z.enum([
    'eoi',
    'welcome_letter',
    'handover_checklist',
    'acknowledgment',
    'correspondence',
    'custom',
  ]),
  templateFormat: z.enum(templateFormats).default('html'),
  bodyHtml: z.string().min(1).optional(),
  mergeFields: mergeFieldsSchema,
  isActive: z.boolean().default(true),
});

export const createTemplateSchema = createTemplateBaseSchema.refine(
  (data) => data.templateFormat !== 'html' || (data.bodyHtml && data.bodyHtml.length > 0),
  { path: ['bodyHtml'], message: 'bodyHtml is required when templateFormat is html' },
);

export const updateTemplateSchema = createTemplateBaseSchema.partial();

export const listTemplatesSchema = baseListQuerySchema.extend({
  templateType: z.string().optional(),
  isActive: z
    .enum(['true', 'false'])
    .transform((v) => v === 'true')
    .optional(),
});

export const generateSchema = z.object({
  clientId: z.string().optional(),
  interestId: z.string().optional(),
  berthId: z.string().optional(),
});

export const generateAndSignSchema = generateSchema.extend({
  pathway: z.enum(['inapp', 'documenso-template']).default('inapp'),
  signers: z
    .array(
      z.object({
        name: z.string().min(1),
        email: z.string().email(),
        role: z.string().min(1),
        signingOrder: z.number().int().min(1),
      }),
    )
    .optional()
    .default([]),
});

export type CreateTemplateInput = z.infer<typeof createTemplateSchema>;
export type UpdateTemplateInput = z.infer<typeof updateTemplateSchema>;
export type ListTemplatesInput = z.infer<typeof listTemplatesSchema>;
export type GenerateInput = z.infer<typeof generateSchema>;
export type GenerateAndSignInput = z.infer<typeof generateAndSignSchema>;

// ─── TipTap-based Admin Template Schemas ─────────────────────────────────────
// Used by /api/v1/admin/templates - the TipTap JSON document store.

export const tiptapDocumentTypes = [
  'eoi',
  'contract',
  'nda',
  'reservation_agreement',
  'letter',
  'other',
] as const;

export const createAdminTemplateSchema = z.object({
  name: z.string().min(1).max(200),
  type: z.enum(tiptapDocumentTypes),
  content: z.record(z.string(), z.unknown()), // TipTap JSON document
});

export const updateAdminTemplateSchema = z.object({
  name: z.string().min(1).max(200).optional(),
  content: z.record(z.string(), z.unknown()).optional(),
  isActive: z.boolean().optional(),
});

export const rollbackAdminTemplateSchema = z.object({
  version: z.number().int().min(1),
});

export const listAdminTemplatesSchema = baseListQuerySchema.extend({
  type: z.enum(tiptapDocumentTypes).optional(),
  isActive: z
    .enum(['true', 'false'])
    .transform((v) => v === 'true')
    .optional(),
});

export type CreateAdminTemplateInput = z.infer<typeof createAdminTemplateSchema>;
export type UpdateAdminTemplateInput = z.infer<typeof updateAdminTemplateSchema>;
export type RollbackAdminTemplateInput = z.infer<typeof rollbackAdminTemplateSchema>;
export type ListAdminTemplatesInput = z.infer<typeof listAdminTemplatesSchema>;
