import { z } from "zod";

// Shared validators
const imageFile = (maxMB: number) =>
  z
    .instanceof(File)
    .refine((f) => f.size <= maxMB * 1024 * 1024, `Max file size is ${maxMB}MB`)
    .refine(
      (f) => ["image/jpeg", "image/png", "image/webp"].includes(f.type),
      "Only .jpg, .png, .webp files are accepted"
    );

const optionalImageFile = (maxMB: number) =>
  z
    .instanceof(File)
    .refine((f) => f.size <= maxMB * 1024 * 1024, `Max file size is ${maxMB}MB`)
    .refine(
      (f) => ["image/jpeg", "image/png", "image/webp"].includes(f.type),
      "Only .jpg, .png, .webp files are accepted"
    )
    .optional()
    .nullable();

// ─── Auth ────────────────────────────────────────────────────────────────────

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

export const registerSchema = z
  .object({
    name: z.string().min(1, "Name is required").max(255),
    email: z.string().email("Invalid email address"),
    password: z
      .string()
      .min(8, "Password must be at least 8 characters")
      .regex(/[a-z]/, "Must contain a lowercase letter")
      .regex(/[A-Z]/, "Must contain an uppercase letter")
      .regex(/[0-9]/, "Must contain a number")
      .regex(/[^a-zA-Z0-9]/, "Must contain a special character"),
    password_confirmation: z.string(),
    phone: z.string().max(20).optional().or(z.literal("")),
    country_of_residence: z.string().max(100).optional().or(z.literal("")),
    city: z.string().max(100).optional().or(z.literal("")),
  })
  .refine((data) => data.password === data.password_confirmation, {
    message: "Passwords don't match",
    path: ["password_confirmation"],
  });

// ─── Company ─────────────────────────────────────────────────────────────────

export const companySchema = z.object({
  category_id: z.string().uuid("Select a category"),
  name: z.string().min(1, "Company name is required").max(255),
  short_description: z.string().max(500).optional().or(z.literal("")),
  description: z.string().max(10000).optional().or(z.literal("")),
  phone: z.string().max(20).optional().or(z.literal("")),
  email: z.string().email("Invalid email").optional().or(z.literal("")),
  website: z.string().url("Invalid URL").optional().or(z.literal("")),
  address: z.string().max(500).optional().or(z.literal("")),
  city: z.string().max(100).optional().or(z.literal("")),
  county: z.string().max(100).optional().or(z.literal("")),
  country: z.string().max(100).optional().or(z.literal("")),
  latitude: z.coerce.number().min(-90).max(90).optional().nullable(),
  longitude: z.coerce.number().min(-180).max(180).optional().nullable(),
  meta_title: z.string().max(70).optional().or(z.literal("")),
  meta_description: z.string().max(160).optional().or(z.literal("")),
});

// ─── Property ────────────────────────────────────────────────────────────────

export const PROPERTY_TYPES = [
  "apartment",
  "house",
  "villa",
  "land",
  "commercial",
  "townhouse",
  "maisonette",
  "bedsitter",
  "studio",
] as const;

export const LISTING_TYPES = ["sale", "rent", "lease"] as const;

export const propertySchema = z.object({
  category_id: z.string().uuid("Select a category"),
  title: z.string().min(1, "Title is required").max(255),
  description: z.string().max(10000).optional().or(z.literal("")),
  short_description: z.string().max(500).optional().or(z.literal("")),
  price: z.coerce.number().min(0, "Price must be positive").max(99999999999.99),
  currency: z.string().length(3).optional().or(z.literal("")),
  price_period: z.enum(["one_time", "monthly", "yearly"]).optional(),
  listing_type: z.enum(LISTING_TYPES, { message: "Select a listing type" }),
  property_type: z.enum(PROPERTY_TYPES, { message: "Select a property type" }),
  bedrooms: z.coerce.number().int().min(0).max(50).optional().nullable(),
  bathrooms: z.coerce.number().int().min(0).max(50).optional().nullable(),
  area_sqft: z.coerce.number().int().min(0).optional().nullable(),
  plot_size_sqft: z.coerce.number().int().min(0).optional().nullable(),
  address: z.string().max(500).optional().or(z.literal("")),
  city: z.string().max(100).optional().or(z.literal("")),
  county: z.string().max(100).optional().or(z.literal("")),
  country: z.string().max(100).optional().or(z.literal("")),
  latitude: z.coerce.number().min(-90).max(90).optional().nullable(),
  longitude: z.coerce.number().min(-180).max(180).optional().nullable(),
  year_built: z.coerce
    .number()
    .int()
    .min(1900)
    .max(new Date().getFullYear() + 5)
    .optional()
    .nullable(),
  is_negotiable: z.boolean().optional(),
  meta_title: z.string().max(70).optional().or(z.literal("")),
  meta_description: z.string().max(160).optional().or(z.literal("")),
});

// ─── Blog Post ───────────────────────────────────────────────────────────────

export const postSchema = z.object({
  category_id: z.string().uuid("Select a category"),
  title: z.string().min(1, "Title is required").max(255),
  excerpt: z.string().max(500).optional().or(z.literal("")),
  body: z.string().min(1, "Content is required"),
  status: z.enum(["draft", "pending", "published"]).optional(),
  is_featured: z.boolean().optional(),
  meta_title: z.string().max(70).optional().or(z.literal("")),
  meta_description: z.string().max(160).optional().or(z.literal("")),
});

// ─── Magazine ────────────────────────────────────────────────────────────────

export const magazineIssueSchema = z.object({
  title: z.string().min(1, "Title is required").max(255),
  description: z.string().max(2000).optional().or(z.literal("")),
  issue_number: z.coerce.number().int().min(1, "Issue number is required"),
  is_free: z.boolean().optional(),
  price: z.coerce.number().min(0).max(99999.99).optional().nullable(),
  currency: z.string().length(3).optional().or(z.literal("")),
  status: z.enum(["draft", "published"]).optional(),
  meta_title: z.string().max(70).optional().or(z.literal("")),
  meta_description: z.string().max(160).optional().or(z.literal("")),
});

export const magazineArticleSchema = z.object({
  issue_id: z.string().uuid("Select an issue"),
  category_id: z.string().uuid().optional().or(z.literal("")),
  title: z.string().min(1, "Title is required").max(255),
  excerpt: z.string().max(500).optional().or(z.literal("")),
  body: z.string().min(1, "Content is required"),
  is_free: z.boolean().optional(),
  sort_order: z.coerce.number().int().min(0).optional().nullable(),
  meta_title: z.string().max(70).optional().or(z.literal("")),
  meta_description: z.string().max(160).optional().or(z.literal("")),
});

// ─── Advertising ─────────────────────────────────────────────────────────────

export const advertisementSchema = z
  .object({
    placement_id: z.string().uuid("Select a placement"),
    title: z.string().min(1, "Title is required").max(255),
    company_name: z.string().max(255).optional().or(z.literal("")),
    target_url: z.string().url("Must be a valid URL").max(500),
    alt_text: z.string().max(255).optional().or(z.literal("")),
    starts_at: z.string().min(1, "Start date is required"),
    ends_at: z.string().min(1, "End date is required"),
  })
  .refine(
    (data) => {
      if (!data.starts_at || !data.ends_at) return true;
      return new Date(data.ends_at) > new Date(data.starts_at);
    },
    { message: "End date must be after start date", path: ["ends_at"] }
  )
  .refine(
    (data) => {
      if (!data.starts_at) return true;
      const today = new Date();
      today.setHours(0, 0, 0, 0);
      return new Date(data.starts_at) >= today;
    },
    { message: "Start date cannot be in the past", path: ["starts_at"] }
  );

// ─── Image validators (for use in form handlers) ─────────────────────────────

export function validateImages(
  files: File[],
  maxCount: number = 20,
  maxSizeMB: number = 5
): string | null {
  if (files.length > maxCount) {
    return `Maximum ${maxCount} images allowed`;
  }
  const allowedTypes = ["image/jpeg", "image/png", "image/webp"];
  for (const file of files) {
    if (!allowedTypes.includes(file.type)) {
      return `${file.name}: Only .jpg, .png, .webp files are accepted`;
    }
    if (file.size > maxSizeMB * 1024 * 1024) {
      return `${file.name}: Max file size is ${maxSizeMB}MB`;
    }
  }
  return null;
}

// Export types
export type LoginInput = z.infer<typeof loginSchema>;
export type RegisterInput = z.infer<typeof registerSchema>;
export type CompanyInput = z.infer<typeof companySchema>;
export type PropertyInput = z.infer<typeof propertySchema>;
export type PostInput = z.infer<typeof postSchema>;
export type MagazineIssueInput = z.infer<typeof magazineIssueSchema>;
export type MagazineArticleInput = z.infer<typeof magazineArticleSchema>;
export type AdvertisementInput = z.infer<typeof advertisementSchema>;
