import { z } from 'zod';

// ---------------------------------------------------------------------------
// Enums
// ---------------------------------------------------------------------------

export const UEBUNG_TYPEN = [
  'Übungsabend',
  'Lehrgang',
  'Sonderdienst',
  'Versammlung',
  'Gemeinschaftsübung',
  'Sonstiges',
] as const;

export type UebungTyp = (typeof UEBUNG_TYPEN)[number];

export const TEILNAHME_STATUSES = [
  'zugesagt',
  'abgesagt',
  'erschienen',
  'entschuldigt',
  'unbekannt',
] as const;

export type TeilnahmeStatus = (typeof TEILNAHME_STATUSES)[number];

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

export interface Uebung {
  id: string;
  titel: string;
  beschreibung?: string | null;
  typ: UebungTyp;
  datum_von: Date;
  datum_bis: Date;
  ort?: string | null;
  treffpunkt?: string | null;
  pflichtveranstaltung: boolean;
  mindest_teilnehmer?: number | null;
  max_teilnehmer?: number | null;
  angelegt_von?: string | null;
  erstellt_am: Date;
  aktualisiert_am: Date;
  abgesagt: boolean;
  absage_grund?: string | null;
}

export interface Teilnahme {
  uebung_id: string;
  user_id: string;
  status: TeilnahmeStatus;
  antwort_am?: Date | null;
  erschienen_erfasst_am?: Date | null;
  erschienen_erfasst_von?: string | null;
  bemerkung?: string | null;
  // Joined from users table
  user_name?: string | null;
  user_email?: string | null;
}

// ---------------------------------------------------------------------------
// Enriched / view-based interfaces
// ---------------------------------------------------------------------------

export interface AttendanceCounts {
  gesamt_eingeladen: number;
  anzahl_zugesagt: number;
  anzahl_abgesagt: number;
  anzahl_erschienen: number;
  anzahl_entschuldigt: number;
  anzahl_unbekannt: number;
}

/** Full event object including all attendance data — used in detail page */
export interface UebungWithAttendance extends Uebung, AttendanceCounts {
  /** Only populated for users with training:write or own role >= Gruppenführer */
  teilnahmen?: Teilnahme[];
  /** The requesting user's own RSVP status, always included */
  eigener_status?: TeilnahmeStatus;
  /** Name of the person who created the event */
  angelegt_von_name?: string | null;
}

/** Lightweight list item — used in calendar, upcoming list widget */
export interface UebungListItem {
  id: string;
  titel: string;
  typ: UebungTyp;
  datum_von: Date;
  datum_bis: Date;
  ort?: string | null;
  pflichtveranstaltung: boolean;
  abgesagt: boolean;
  anzahl_zugesagt: number;
  anzahl_erschienen: number;
  gesamt_eingeladen: number;
  /** Requesting user's own status — undefined when called without userId */
  eigener_status?: TeilnahmeStatus;
}

// ---------------------------------------------------------------------------
// Statistics
// ---------------------------------------------------------------------------

/** Monthly training summary for dashboard stats card */
export interface TrainingStats {
  /** e.g. "2026-02" */
  month: string;
  /** Total events that month */
  total: number;
  /** Pflichtveranstaltungen that month */
  pflicht: number;
  /** % of events (Übungsabende only) a given user attended — 0-100 */
  attendanceRate: number;
}

/** Per-member annual participation stats for Jahresbericht (Tier 3) */
export interface MemberParticipationStats {
  userId: string;
  name: string;
  totalUebungen: number;
  attended: number;
  attendancePercent: number;
  pflichtGesamt: number;
  pflichtErschienen: number;
  uebungsabendQuotePct: number;
}

// ---------------------------------------------------------------------------
// Zod validation schemas — used in service layer and route middleware
// ---------------------------------------------------------------------------

const UebungBaseSchema = z.object({
  titel: z
    .string()
    .min(3, 'Titel muss mindestens 3 Zeichen haben')
    .max(255),
  beschreibung: z.string().max(5000).optional().nullable(),
  typ: z.enum(UEBUNG_TYPEN),
  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)),
  ort: z.string().max(255).optional().nullable(),
  treffpunkt: z.string().max(255).optional().nullable(),
  pflichtveranstaltung: z.boolean().default(false),
  mindest_teilnehmer: z.number().int().positive().optional().nullable(),
  max_teilnehmer: z.number().int().positive().optional().nullable(),
});

export const CreateUebungSchema = UebungBaseSchema.refine(
  (d) => d.datum_bis >= d.datum_von,
  { message: 'datum_bis muss nach datum_von liegen', path: ['datum_bis'] }
).refine(
  (d) =>
    d.max_teilnehmer == null ||
    d.mindest_teilnehmer == null ||
    d.max_teilnehmer >= d.mindest_teilnehmer,
  { message: 'max_teilnehmer muss >= mindest_teilnehmer sein', path: ['max_teilnehmer'] }
);

export type CreateUebungData = z.infer<typeof CreateUebungSchema>;

export const UpdateUebungSchema = UebungBaseSchema.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'] }
).refine(
  (d) =>
    d.max_teilnehmer == null ||
    d.mindest_teilnehmer == null ||
    d.max_teilnehmer >= d.mindest_teilnehmer,
  { message: 'max_teilnehmer muss >= mindest_teilnehmer sein', path: ['max_teilnehmer'] }
);

export type UpdateUebungData = z.infer<typeof UpdateUebungSchema>;

export const UpdateRsvpSchema = z.object({
  status: z.enum(['zugesagt', 'abgesagt']),
  bemerkung: z.string().max(500).optional().nullable(),
});

export type UpdateRsvpData = z.infer<typeof UpdateRsvpSchema>;

export const MarkAttendanceSchema = z.object({
  userIds: z
    .array(z.string().uuid())
    .min(1, 'Mindestens eine Person muss ausgewählt werden'),
});

export type MarkAttendanceData = z.infer<typeof MarkAttendanceSchema>;

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

export type CancelEventData = z.infer<typeof CancelEventSchema>;
