import { z } from "zod";

// ============================================================================
// Common validation rules
// ============================================================================

export const emailSchema = z.string().email("Invalid email address");

export const passwordSchema = z
  .string()
  .min(8, "Password must be at least 8 characters")
  .regex(/[A-Z]/, "Password must contain at least one uppercase letter")
  .regex(/[a-z]/, "Password must contain at least one lowercase letter")
  .regex(/[0-9]/, "Password must contain at least one number");

export const phoneSchema = z
  .string()
  .optional()
  .refine((val) => !val || /^\+?[1-9]\d{1,14}$/.test(val), {
    message: "Invalid phone number format",
  });

export const dateTimeSchema = z.string().datetime("Invalid datetime format");

// ============================================================================
// User schemas
// ============================================================================

export const userRoleSchema = z.enum([
  "client",
  "trainer",
  "admin",
  "superAdmin",
]);

export const userSchema = z.object({
  email: emailSchema,
  password: passwordSchema,
  firstName: z.string().min(1, "First name is required").max(50),
  lastName: z.string().min(1, "Last name is required").max(50),
  phone: phoneSchema,
  role: userRoleSchema.default("client"),
});

export const userUpdateSchema = userSchema.partial();

export const userLoginSchema = z.object({
  email: emailSchema,
  password: z.string().min(1, "Password is required"),
});

export const userInviteSchema = z.object({
  email: emailSchema,
  firstName: z.string().min(1, "First name is required").max(50),
  lastName: z.string().min(1, "Last name is required").max(50),
  role: userRoleSchema,
  phone: phoneSchema,
});

export const userUpdateWithIdSchema = z.object({
  id: z.string().min(1, "User ID is required"),
  email: emailSchema.optional(),
  firstName: z.string().min(1, "First name is required").max(50).optional(),
  lastName: z.string().min(1, "Last name is required").max(50).optional(),
  role: userRoleSchema.optional(),
  phone: phoneSchema,
  gymId: z.string().nullable().optional(),
});

// ============================================================================
// Fitness Goal schemas
// ============================================================================

export const goalTypeSchema = z.enum([
  "weight_target",
  "strength_milestone",
  "endurance_target",
  "flexibility_goal",
  "habit_building",
  "custom",
]);

export const prioritySchema = z.enum(["low", "medium", "high"]);

export const goalStatusSchema = z.enum(["active", "completed", "abandoned"]);

export const fitnessGoalSchema = z.object({
  userId: z.string().min(1, "User ID is required").optional(), // Optional for authenticated requests
  goalType: goalTypeSchema,
  title: z.string().min(1, "Title is required").max(100),
  description: z.string().max(500).optional(),
  targetValue: z.number().positive("Target value must be positive").optional(),
  currentValue: z
    .number()
    .nonnegative("Current value cannot be negative")
    .optional(),
  unit: z.string().max(20).optional(),
  targetDate: dateTimeSchema.optional(),
  priority: prioritySchema.default("medium"),
  status: goalStatusSchema.default("active"),
  notes: z.string().max(1000).optional(),
});

export const fitnessGoalUpdateSchema = fitnessGoalSchema
  .omit({ userId: true })
  .partial();

// ============================================================================
// Fitness Profile schemas
// ============================================================================

export const genderSchema = z.enum([
  "male",
  "female",
  "other",
  "prefer_not_to_say",
]);

export const activityLevelSchema = z.enum([
  "sedentary",
  "lightly_active",
  "moderately_active",
  "very_active",
  "extremely_active",
]);

export const fitnessProfileSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  height: z
    .number()
    .positive("Height must be positive")
    .max(300, "Invalid height value"),
  weight: z
    .number()
    .positive("Weight must be positive")
    .max(500, "Invalid weight value"),
  age: z
    .number()
    .int("Age must be an integer")
    .positive("Age must be positive")
    .min(13, "Must be at least 13 years old")
    .max(120, "Invalid age value"),
  gender: genderSchema.optional(),
  activityLevel: activityLevelSchema.optional(),
  fitnessGoals: z
    .array(z.string())
    .max(10, "Maximum 10 goals allowed")
    .optional(),
  medicalConditions: z.string().max(1000).optional(),
  allergies: z.string().max(500).optional(),
  injuries: z.string().max(500).optional(),
  preferences: z.string().max(1000).optional(),
});

export const fitnessProfileUpdateSchema = fitnessProfileSchema
  .omit({ userId: true })
  .partial();

// ============================================================================
// Recommendation schemas
// ============================================================================

export const recommendationTypeSchema = z.enum([
  "workout",
  "nutrition",
  "lifestyle",
  "recovery",
]);

export const recommendationStatusSchema = z.enum([
  "pending",
  "accepted",
  "rejected",
  "completed",
]);

export const recommendationSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  type: recommendationTypeSchema,
  title: z.string().min(1, "Title is required").max(200),
  description: z.string().min(1, "Description is required").max(2000),
  reasoning: z.string().max(1000).optional(),
  priority: prioritySchema.default("medium"),
  status: recommendationStatusSchema.default("pending"),
  metadata: z.record(z.string(), z.unknown()).optional(),
  aiGenerated: z.boolean().default(false),
});

export const recommendationUpdateSchema = recommendationSchema.partial().omit({
  userId: true,
});

export const generateRecommendationSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  type: recommendationTypeSchema.optional(),
  count: z
    .number()
    .int()
    .positive()
    .min(1)
    .max(10, "Maximum 10 recommendations per request")
    .default(3),
  includeContext: z.boolean().default(true),
});

// Legacy recommendation schema for backward compatibility
export const legacyRecommendationSchema = z
  .object({
    userId: z.string().min(1, "User ID is required"),
    fitnessProfileId: z.string().optional(),
    recommendationText: z.string().min(1).max(5000).optional(),
    activityPlan: z.string().max(5000).optional(),
    dietPlan: z.string().max(5000).optional(),
    type: z.string().optional(),
    content: z.string().max(5000).optional(),
    status: recommendationStatusSchema.optional(),
  })
  .refine(
    (data) =>
      (data.recommendationText && data.activityPlan && data.dietPlan) ||
      (data.type && data.content),
    {
      message:
        "Either provide (recommendationText, activityPlan, dietPlan) or (type, content)",
    },
  );

export const recommendationUpdateRequestSchema = z.object({
  id: z.string().min(1, "Recommendation ID is required"),
  status: recommendationStatusSchema.optional(),
  recommendationText: z.string().max(5000).optional(),
  activityPlan: z.string().max(5000).optional(),
  dietPlan: z.string().max(5000).optional(),
  content: z.string().max(5000).optional(),
});

// ============================================================================
// Attendance schemas
// ============================================================================

export const attendanceSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  gymId: z.string().min(1, "Gym ID is required"),
  checkInTime: dateTimeSchema,
  checkOutTime: dateTimeSchema.optional(),
});

export const checkInSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  gymId: z.string().min(1, "Gym ID is required"),
});

export const checkOutSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  attendanceId: z.string().min(1, "Attendance ID is required"),
});

// ============================================================================
// Gym schemas
// ============================================================================

export const gymSchema = z.object({
  name: z.string().min(1, "Gym name is required").max(100),
  address: z.string().min(1, "Address is required").max(200),
  city: z.string().min(1, "City is required").max(100),
  state: z.string().min(2, "State is required").max(50),
  zipCode: z
    .string()
    .regex(/^\d{5}(-\d{4})?$/, "Invalid ZIP code format")
    .optional(),
  phone: phoneSchema,
  email: emailSchema.optional(),
  capacity: z.number().int().positive("Capacity must be positive").optional(),
  amenities: z.array(z.string()).max(50).optional(),
  operatingHours: z.string().max(500).optional(),
});

export const gymUpdateSchema = gymSchema.partial();

export const assignUserToGymSchema = z.object({
  userId: z.string().min(1, "User ID is required"),
  gymId: z.string().min(1, "Gym ID is required"),
});

// ============================================================================
// Invitation schemas
// ============================================================================

export const invitationSchema = z.object({
  email: emailSchema,
  role: z.enum(["client", "trainer"]).default("client"),
  gymId: z.string().min(1, "Gym ID is required").optional(),
  expiresAt: dateTimeSchema.optional(),
  message: z.string().max(500).optional(),
});

export const invitationUpdateSchema = z.object({
  status: z.enum(["pending", "accepted", "rejected", "expired"]),
});

// ============================================================================
// Query parameter schemas
// ============================================================================

export const paginationSchema = z.object({
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
  sortBy: z.string().optional(),
  sortOrder: z.enum(["asc", "desc"]).default("asc"),
});

export const statusFilterSchema = z
  .enum(["active", "completed", "all"])
  .default("all");

export const roleFilterSchema = z
  .enum(["client", "trainer", "admin", "superAdmin", "all"])
  .default("all");

export const dateRangeSchema = z.object({
  startDate: dateTimeSchema.optional(),
  endDate: dateTimeSchema.optional(),
});

export const searchSchema = z.object({
  query: z.string().min(1).max(100),
  fields: z.array(z.string()).max(10).optional(),
});

// ============================================================================
// Type exports (inferred from schemas)
// ============================================================================

export type User = z.infer<typeof userSchema>;
export type UserUpdate = z.infer<typeof userUpdateSchema>;
export type UserLogin = z.infer<typeof userLoginSchema>;
export type UserRole = z.infer<typeof userRoleSchema>;

export type FitnessGoal = z.infer<typeof fitnessGoalSchema>;
export type FitnessGoalUpdate = z.infer<typeof fitnessGoalUpdateSchema>;
export type GoalType = z.infer<typeof goalTypeSchema>;
export type GoalStatus = z.infer<typeof goalStatusSchema>;

export type FitnessProfile = z.infer<typeof fitnessProfileSchema>;
export type FitnessProfileUpdate = z.infer<typeof fitnessProfileUpdateSchema>;
export type Gender = z.infer<typeof genderSchema>;
export type ActivityLevel = z.infer<typeof activityLevelSchema>;

export type Recommendation = z.infer<typeof recommendationSchema>;
export type RecommendationUpdate = z.infer<typeof recommendationUpdateSchema>;
export type RecommendationType = z.infer<typeof recommendationTypeSchema>;
export type RecommendationStatus = z.infer<typeof recommendationStatusSchema>;
export type GenerateRecommendation = z.infer<
  typeof generateRecommendationSchema
>;

export type Attendance = z.infer<typeof attendanceSchema>;
export type CheckIn = z.infer<typeof checkInSchema>;
export type CheckOut = z.infer<typeof checkOutSchema>;

export type Gym = z.infer<typeof gymSchema>;
export type GymUpdate = z.infer<typeof gymUpdateSchema>;
export type AssignUserToGym = z.infer<typeof assignUserToGymSchema>;

export type Invitation = z.infer<typeof invitationSchema>;
export type InvitationUpdate = z.infer<typeof invitationUpdateSchema>;

export type Pagination = z.infer<typeof paginationSchema>;
export type StatusFilter = z.infer<typeof statusFilterSchema>;
export type RoleFilter = z.infer<typeof roleFilterSchema>;
export type DateRange = z.infer<typeof dateRangeSchema>;
export type Search = z.infer<typeof searchSchema>;
export type Priority = z.infer<typeof prioritySchema>;
