import { z } from 'zod';

// ---------------------------------------------------------------------------
// Core DB-mapped interfaces
// ---------------------------------------------------------------------------

export interface VeranstaltungKategorie {
  id: string;
  name: string;
  beschreibung?: string | null;
  farbe?: string | null;
  icon?: string | null;
  zielgruppen: string[];
  alle_gruppen: boolean;
  erstellt_von?: string | null;
  erstellt_am: Date;
  aktualisiert_am: Date;
}

export interface Veranstaltung {
  id: string;
  titel: string;
  beschreibung?: string | null;
  ort?: string | null;
  ort_url?: string | null;
  kategorie_id?: string | null;
  datum_von: Date;
  datum_bis: Date;
  ganztaegig: boolean;
  zielgruppen: string[];
  alle_gruppen: boolean;
  max_teilnehmer?: number | null;
  anmeldung_erforderlich: boolean;
  anmeldung_bis?: Date | null;
  erstellt_von: string;
  abgesagt: boolean;
  abgesagt_grund?: string | null;
  abgesagt_am?: Date | null;
  erstellt_am: Date;
  aktualisiert_am: Date;
  // Joined / enriched fields
  kategorie_name?: string | null;
  kategorie_farbe?: string | null;
  kategorie_icon?: string | null;
  erstellt_von_name?: string | null;
  // Recurrence fields
  wiederholung?: WiederholungConfig | null;
  wiederholung_parent_id?: string | null;
}

export interface WiederholungConfig {
  typ: 'wöchentlich' | 'zweiwöchentlich' | 'monatlich_datum' | 'monatlich_erster_wochentag' | 'monatlich_letzter_wochentag';
  intervall?: number;
  bis: string;
  wochentag?: number;
}

/** Lightweight version for calendar and list views */
export interface VeranstaltungListItem {
  id: string;
  titel: string;
  ort?: string | null;
  kategorie_id?: string | null;
  kategorie_name?: string | null;
  kategorie_farbe?: string | null;
  kategorie_icon?: string | null;
  datum_von: Date;
  datum_bis: Date;
  ganztaegig: boolean;
  alle_gruppen: boolean;
  zielgruppen: string[];
  abgesagt: boolean;
  anmeldung_erforderlich: boolean;
  // Recurrence fields
  wiederholung?: WiederholungConfig | null;
  wiederholung_parent_id?: string | null;
}

// ---------------------------------------------------------------------------
// Zod schemas -- Kategorien
// ---------------------------------------------------------------------------

export const CreateKategorieSchema = z.object({
  name: z
    .string()
    .min(2, 'Name muss mindestens 2 Zeichen haben')
    .max(255),
  beschreibung: z.string().max(500).optional().nullable(),
  farbe: z
    .string()
    .regex(/^#[0-9a-fA-F]{6}$/, 'Farbe muss ein gültiger Hex-Farbwert sein (z.B. #1976d2)')
    .optional(),
  icon: z.string().max(100).optional(),
  zielgruppen: z.array(z.string()).optional(),
  alle_gruppen: z.boolean().optional(),
});

export type CreateKategorieData = z.infer<typeof CreateKategorieSchema>;

export const UpdateKategorieSchema = CreateKategorieSchema.partial();

export type UpdateKategorieData = z.infer<typeof UpdateKategorieSchema>;

// ---------------------------------------------------------------------------
// Zod schemas -- Veranstaltungen
// ---------------------------------------------------------------------------

const VeranstaltungBaseSchema = z.object({
  titel: z
    .string()
    .min(3, 'Titel muss mindestens 3 Zeichen haben')
    .max(500),
  beschreibung: z.string().max(5000).optional().nullable(),
  ort: z.string().max(500).optional().nullable(),
  // Plain string validator — some users use relative paths or internal URLs
  ort_url: z.string().max(1000).optional().nullable(),
  kategorie_id: z.string().uuid('kategorie_id muss eine gültige UUID sein').optional().nullable(),
  datum_von: z
    .string()
    .datetime({ offset: true, message: 'datum_von muss ein ISO-8601 Datum mit Zeitzone sein' })
    .transform((s) => new Date(s)),
  datum_bis: z
    .string()
    .datetime({ offset: true, message: 'datum_bis muss ein ISO-8601 Datum mit Zeitzone sein' })
    .transform((s) => new Date(s)),
  ganztaegig: z.boolean().default(false),
  zielgruppen: z.array(z.string()).default([]),
  alle_gruppen: z.boolean().default(false),
  max_teilnehmer: z.number().int().positive().optional().nullable(),
  anmeldung_erforderlich: z.boolean().default(false),
  anmeldung_bis: z
    .string()
    .datetime({ offset: true, message: 'anmeldung_bis muss ein ISO-8601 Datum mit Zeitzone sein' })
    .transform((s) => new Date(s))
    .optional()
    .nullable(),
  wiederholung: z.object({
    typ: z.enum(['wöchentlich', 'zweiwöchentlich', 'monatlich_datum', 'monatlich_erster_wochentag', 'monatlich_letzter_wochentag']),
    intervall: z.number().int().min(1).max(52).optional(),
    bis: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'bis muss ein Datum (YYYY-MM-DD) sein'),
    wochentag: z.number().int().min(0).max(6).optional(),
  }).optional().nullable(),
});

export const CreateVeranstaltungSchema = VeranstaltungBaseSchema.refine(
  (d) => d.datum_bis >= d.datum_von,
  { message: 'datum_bis muss nach datum_von liegen', path: ['datum_bis'] }
);

export type CreateVeranstaltungData = z.infer<typeof CreateVeranstaltungSchema>;

export const UpdateVeranstaltungSchema = VeranstaltungBaseSchema.partial().refine(
  (d) => d.datum_bis == null || d.datum_von == null || d.datum_bis >= d.datum_von,
  { message: 'datum_bis muss nach datum_von liegen', path: ['datum_bis'] }
);

export type UpdateVeranstaltungData = z.infer<typeof UpdateVeranstaltungSchema>;

export const CancelVeranstaltungSchema = z.object({
  abgesagt_grund: z
    .string()
    .min(5, 'Bitte gib einen Grund für die Absage an (min. 5 Zeichen)')
    .max(1000),
});

export type CancelVeranstaltungData = z.infer<typeof CancelVeranstaltungSchema>;
