import { z } from 'zod';

export const createInstanceSchema = z.object({
  name: z.string().min(2).max(100).regex(/^[a-zA-Z0-9 '_\-.]+$/, 'Name contains invalid characters'),
  slug: z.string().min(2).max(50).regex(/^[a-z0-9-]+$/, 'Slug must be lowercase alphanumeric with hyphens'),
  domain: z.string().min(3).max(255).regex(/^[a-zA-Z0-9.\-]+$/, 'Domain must be a valid hostname'),
  adminEmail: z.string().email(),
  enableMedia: z.boolean().default(false),
  enableChat: z.boolean().default(false),
  enableGancio: z.boolean().default(false),
  enableListmonk: z.boolean().default(false),
  enableMonitoring: z.boolean().default(false),
  enableDevTools: z.boolean().default(false),
  enablePayments: z.boolean().default(false),
  enableMeet: z.boolean().default(false),
  enableSms: z.boolean().default(false),
  enableSocial: z.boolean().default(false),
  enablePeople: z.boolean().default(false),
  enableAnalytics: z.boolean().default(false),
  jvbAdvertiseIp: z.string().ip({ version: 'v4' }).optional(),
  smtpHost: z.string().regex(/^[a-zA-Z0-9.\-]+$/, 'SMTP host must be a valid hostname').optional(),
  smtpPort: z.coerce.number().optional(),
  smtpUser: z.string().optional(),
  smtpFrom: z.string().optional(),
  emailTestMode: z.boolean().default(true),
  enablePangolin: z.boolean().default(false),
  pangolinEndpoint: z.string().url().optional(),
  pangolinNewtId: z.string().optional(),
  pangolinNewtSecret: z.string().optional(),
  notes: z.string().optional(),
});

export const updateInstanceSchema = z.object({
  name: z.string().min(2).max(100).regex(/^[a-zA-Z0-9 '_\-.]+$/, 'Name contains invalid characters').optional(),
  enableMedia: z.boolean().optional(),
  enableChat: z.boolean().optional(),
  enableGancio: z.boolean().optional(),
  enableListmonk: z.boolean().optional(),
  enableMonitoring: z.boolean().optional(),
  enableDevTools: z.boolean().optional(),
  enablePayments: z.boolean().optional(),
  enableMeet: z.boolean().optional(),
  enableSms: z.boolean().optional(),
  enableSocial: z.boolean().optional(),
  enablePeople: z.boolean().optional(),
  enableAnalytics: z.boolean().optional(),
  jvbAdvertiseIp: z.string().ip({ version: 'v4' }).nullable().optional(),
  smtpHost: z.string().regex(/^[a-zA-Z0-9.\-]+$/, 'SMTP host must be a valid hostname').optional(),
  smtpPort: z.coerce.number().optional(),
  smtpUser: z.string().optional(),
  smtpFrom: z.string().optional(),
  emailTestMode: z.boolean().optional(),
  notes: z.string().nullable().optional(),
});

export const registerInstanceSchema = z.object({
  name: z.string().min(2).max(100).regex(/^[a-zA-Z0-9 '_\-.]+$/, 'Name contains invalid characters'),
  slug: z.string().min(2).max(50).regex(/^[a-z0-9-]+$/, 'Slug must be lowercase alphanumeric with hyphens'),
  domain: z.string().min(3).max(255).regex(/^[a-zA-Z0-9.\-]+$/, 'Domain must be a valid hostname'),
  basePath: z.string().min(1),
  composeProject: z.string().min(1),
  portConfig: z.object({
    api: z.coerce.number().int().min(1).max(65535),
    admin: z.coerce.number().int().min(1).max(65535),
    postgres: z.coerce.number().int().min(1).max(65535),
    nginx: z.coerce.number().int().min(1).max(65535),
    embed: z.coerce.number().int().min(1).max(65535).optional(),
  }),
  adminEmail: z.string().email().optional().default('admin@localhost'),
  enableMedia: z.boolean().default(false),
  enableChat: z.boolean().default(false),
  enableGancio: z.boolean().default(false),
  enableListmonk: z.boolean().default(false),
  enableMonitoring: z.boolean().default(false),
  enableDevTools: z.boolean().default(false),
  enablePayments: z.boolean().default(false),
  enableMeet: z.boolean().default(false),
  enableSms: z.boolean().default(false),
  enableSocial: z.boolean().default(false),
  enablePeople: z.boolean().default(false),
  enableAnalytics: z.boolean().default(false),
  emailTestMode: z.boolean().default(true),
  notes: z.string().optional(),
});

export const reconfigureInstanceSchema = z.object({
  enableMedia: z.boolean().optional(),
  enableChat: z.boolean().optional(),
  enableGancio: z.boolean().optional(),
  enableListmonk: z.boolean().optional(),
  enableMonitoring: z.boolean().optional(),
  enableDevTools: z.boolean().optional(),
  enablePayments: z.boolean().optional(),
  enableMeet: z.boolean().optional(),
  enableSms: z.boolean().optional(),
  enableSocial: z.boolean().optional(),
  enablePeople: z.boolean().optional(),
  enableAnalytics: z.boolean().optional(),
});

export const configureTunnelSchema = z.object({
  pangolinEndpoint: z.string().url(),
  pangolinNewtId: z.string().min(1),
  pangolinNewtSecret: z.string().min(1).optional(),
});

export const importInstancesSchema = z.object({
  instances: z.array(registerInstanceSchema).min(1).max(50),
});

// SECURITY: branch name is interpolated into a shell command string in the
// local `runUpgrade` path (exec, not spawn), so we must enforce the same
// strict allow-list the agent uses on its own end. This blocks names starting
// with `-` (avoiding flag confusion), shell metachars, and anything exotic.
export const startUpgradeSchema = z.object({
  skipBackup: z.boolean().optional(),
  useRegistry: z.boolean().optional(),
  branch: z
    .string()
    .regex(/^[a-zA-Z0-9][a-zA-Z0-9_.\/-]{0,99}$/, 'Invalid branch name')
    .optional(),
});

// Approach B: image-only upgrade. Pulls images + recreates core app services
// without touching tracked files. imageTag is optional — if omitted, the
// agent uses whatever IMAGE_TAG the install's .env / compose env defines
// (typically `latest`). Tag must be a valid Docker tag.
export const startImageUpgradeSchema = z.object({
  imageTag: z
    .string()
    .regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/, 'Invalid imageTag')
    .optional(),
});

// Approach C: release upgrade via CCP template re-render. CCP renders the
// docker-compose.yml + nginx confs + pangolin resources etc. against the
// tenant's context (with the proposed imageTag), writes them to the tenant,
// then composePull + composeUp. Used when a release changes orchestration
// in addition to image versions. imageTag is the new value for the
// per-instance Instance.imageTag column (NULL falls back to env default).
export const startReleaseUpgradeSchema = z.object({
  imageTag: z
    .string()
    .regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/, 'Invalid imageTag')
    .optional(),
});

export const setupRemoteTunnelSchema = z.object({
  // Empty string or omitted → resources use standard subdomains (app., api., etc.)
  // A value like "ck" → creates ck-app., ck-api., etc. for multi-tenant domains
  subdomainPrefix: z
    .string()
    .max(50)
    .regex(/^[a-z0-9-]*$/, 'Prefix must be lowercase alphanumeric with hyphens')
    .optional(),
});

export type CreateInstanceInput = z.infer<typeof createInstanceSchema>;
export type UpdateInstanceInput = z.infer<typeof updateInstanceSchema>;
export type RegisterInstanceInput = z.infer<typeof registerInstanceSchema>;
export type ReconfigureInstanceInput = z.infer<typeof reconfigureInstanceSchema>;
export type ConfigureTunnelInput = z.infer<typeof configureTunnelSchema>;
export type ImportInstancesInput = z.infer<typeof importInstancesSchema>;
export type StartUpgradeInput = z.infer<typeof startUpgradeSchema>;
