import { z } from 'zod';

/**
 * Pilot application: field list, validation and form-state types. Pure (no I/O), shared by the
 * client form and the server action, and unit-tested in pilot.test.ts.
 */

export const NIGHTS = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'] as const;
export type Night = (typeof NIGHTS)[number];

export const NIGHT_LABELS: Record<Night, string> = {
  MON: 'Mon',
  TUE: 'Tue',
  WED: 'Wed',
  THU: 'Thu',
  FRI: 'Fri',
  SAT: 'Sat',
  SUN: 'Sun',
};

/** Hidden field real people never see; anything typed into it marks the submission as a bot. */
export const HONEYPOT_FIELD = 'extra_info';
/** Hidden field carrying the signed issue time (see form-token.ts). */
export const TOKEN_FIELD = 'form_token';

export const PILOT_FIELDS = [
  'venueName',
  'address',
  'contactName',
  'email',
  'phone',
  'tvCount',
  'busiestNights',
  'currentEntertainment',
  'message',
] as const;
export type PilotField = (typeof PILOT_FIELDS)[number];

/** Raw values as typed, used to re-fill the form after a failed submit. */
export interface PilotFormValues {
  venueName: string;
  address: string;
  contactName: string;
  email: string;
  phone: string;
  tvCount: string;
  busiestNights: string[];
  currentEntertainment: string;
  message: string;
}

export type PilotFieldErrors = Partial<Record<PilotField, string>>;

export type PilotFormState =
  | { status: 'idle' }
  | { status: 'error'; message: string; fieldErrors: PilotFieldErrors; values: PilotFormValues }
  | { status: 'success'; venueName: string; email: string };

const optionalText = (max: number, label: string) =>
  z
    .string()
    .trim()
    .max(max, `Please keep ${label} under ${max} characters.`)
    .transform((value) => (value.length > 0 ? value : null));

export const pilotLeadSchema = z.object({
  venueName: z
    .string()
    .trim()
    .min(2, 'Tell us the name of your venue.')
    .max(120, 'Please keep the venue name under 120 characters.'),
  address: z
    .string()
    .trim()
    .min(5, 'Add the street address and town so we know where you are.')
    .max(200, 'Please keep the address under 200 characters.'),
  contactName: z
    .string()
    .trim()
    .min(2, 'Who should we talk to? Add your name.')
    .max(80, 'Please keep your name under 80 characters.'),
  email: z
    .string()
    .trim()
    .min(1, 'Add an email address so we can reply.')
    .max(254, 'That email address is too long.')
    .pipe(z.email('Enter a valid email address, like you@yourbar.com.'))
    .transform((value) => value.toLowerCase()),
  phone: z
    .string()
    .trim()
    .max(32, 'That phone number is too long.')
    .regex(/^[0-9+().\-\s]*$/, 'Use digits, spaces and + ( ) - only.')
    .refine((value) => value === '' || value.replace(/\D/g, '').length >= 7, 'That phone number looks too short.')
    .transform((value) => (value.length > 0 ? value : null)),
  tvCount: z
    .string()
    .trim()
    .min(1, 'How many TVs could show the game?')
    .regex(/^\d+$/, 'Use a whole number, like 3.')
    .transform(Number)
    .pipe(z.number().int().min(1, 'You’ll need at least one TV.').max(200, 'For more than 200 TVs, tell us in the message.')),
  busiestNights: z
    .array(z.enum(NIGHTS, 'Pick nights from the list.'))
    .min(1, 'Pick at least one night.')
    .max(NIGHTS.length)
    // Stable Mon→Sun order and no duplicates, whatever order the browser posted.
    .transform((nights) => NIGHTS.filter((night) => nights.includes(night))),
  currentEntertainment: optionalText(300, 'this answer'),
  message: optionalText(2000, 'your message'),
});

export type PilotLeadInput = z.output<typeof pilotLeadSchema>;

function text(formData: FormData, name: string): string {
  const value = formData.get(name);
  return typeof value === 'string' ? value : '';
}

export function readPilotFormValues(formData: FormData): PilotFormValues {
  return {
    venueName: text(formData, 'venueName'),
    address: text(formData, 'address'),
    contactName: text(formData, 'contactName'),
    email: text(formData, 'email'),
    phone: text(formData, 'phone'),
    tvCount: text(formData, 'tvCount'),
    busiestNights: formData.getAll('busiestNights').filter((value): value is string => typeof value === 'string'),
    currentEntertainment: text(formData, 'currentEntertainment'),
    message: text(formData, 'message'),
  };
}

export type PilotValidation = { ok: true; data: PilotLeadInput } | { ok: false; fieldErrors: PilotFieldErrors };

/** Validate raw values; on failure returns the first friendly message per field. */
export function validatePilotLead(values: PilotFormValues): PilotValidation {
  const result = pilotLeadSchema.safeParse(values);
  if (result.success) return { ok: true, data: result.data };
  const fieldErrors: PilotFieldErrors = {};
  for (const issue of result.error.issues) {
    const field = issue.path[0];
    if (typeof field === 'string' && (PILOT_FIELDS as readonly string[]).includes(field)) {
      const key = field as PilotField;
      fieldErrors[key] ??= issue.message;
    }
  }
  return { ok: false, fieldErrors };
}

/** True when the honeypot was filled in (bots fill every field they find). */
export function isHoneypotTripped(formData: FormData): boolean {
  return text(formData, HONEYPOT_FIELD).trim().length > 0;
}
