import { z } from "zod";
import { asNumberOrUndef } from "./common.schema";

const facilityItemSchema = z.object({
  name: z.string(),
  address: z.string(),
  distance: z.string(),
  coordinates: z.tuple([z.number(), z.number()]),
});

// Basic Details Schema
const basicDetailsSchema = z.object({
  title: z
    .string({
      required_error: "Property title is required",
    })
    .min(10, "Property title must be at least 10 characters"),
  description: z.string().optional(),
  project: z
    .string({
      required_error: "Project name is required",
    })
    .min(1, "Project name is required"),
  propertyType: z
    .string({
      required_error: "Property type is required",
    })
    .min(1, "Property type is required"),
  subcategory: z
    .string({
      required_error: "Subcategory is required",
    })
    .min(1, "Subcategory is required"),
  reraId: z.string().optional(),
  configuration: z
    .string({
      required_error: "Configuration is required",
    })
    .min(1, "Configuration is required"),
  listingType: z
    .string({
      required_error: "Listing type is required",
    })
    .min(1, "Listing type is required"),
});

// Location & Owner Schema
const locationOwnerSchema = z.object({
  address: z.string().min(10, "Address must be at least 10 characters"),
  locality: z
    .string({ required_error: "Locality is required" })
    .min(2, "Locality is required"),
  city: z
    .string({
      required_error: "City is required",
    })
    .min(2, "City is required"),
  pincode: z.preprocess((val) => {
    if (typeof val === "string" && val.trim() !== "") {
      const num = Number(val);
      return isNaN(num) ? undefined : num;
    }
    return val;
  }, z.number({ required_error: "Pincode is required" }).int("Pincode must be an integer").gte(100000, "Pincode must be exactly 6 digits").lte(999999, "Pincode must be exactly 6 digits")),
  landZoneType: z.string().optional(),
});

// Property Details Schema
const propertyDetailsSchema = z.object({
  carpetArea: z.preprocess((val) => {
    return typeof val === "number" && !isNaN(val) ? val : undefined;
  }, z.number({ required_error: "Carpet area is required" }).min(1, "Carpet area must be at least 1")),
  builtUpArea: z.preprocess((val) => {
    return typeof val === "number" && !isNaN(val) ? val : undefined;
  }, z.number({ required_error: "Built up area is required" }).min(1, "Built up area must be at least 1")),
  superBuiltUpArea: z.preprocess((val) => {
    return typeof val === "number" && !isNaN(val) ? val : undefined;
  }, z.number().min(1, "Super built up area must be at least 1").optional()),
  bedrooms: z.string().optional(),
  bathrooms: z.string().optional(),
  balconies: z.string().optional(),
  totalFloors: z.preprocess((val) => {
    return typeof val === "number" && !isNaN(val) ? val : undefined;
  }, z.number().min(1, "Total floors must be at least 1").optional()),
  floorNumber: z.preprocess((val) => {
    return typeof val === "number" && !isNaN(val) ? val : undefined;
  }, z.number().min(0, "Floor number must be at least 0").optional()),
  carParking: z.string().optional(),
  furnishingStatus: z.string().optional(),
  ageOfProperty: z.string().optional(),
  facing: z.string().optional(),
  possessionStatus: z.string().optional(),
  ownerName: z
    .string({
      required_error: "Owner name is required",
    })
    .min(2, "Owner name must be at least 2 characters"),
  ownerEmail: z.preprocess((val) => {
    return typeof val === "string" && val.trim() !== "" ? val : undefined;
  }, z.string().email("Invalid email address").optional()),
  ownerContact: z.string().min(10, "Contact number must be at least 10 digits"),
});

export const commonPropertyDetailsSchema = z.object({
  ownerName: z
    .string({
      required_error: "Owner name is required",
    })
    .min(2, "Owner name must be at least 2 characters"),
  ownerContact: z.preprocess((val) => {
    if (typeof val === "string" && val.trim() !== "") {
      const num = Number(val);
      return isNaN(num) ? undefined : num;
    }
    return val;
  }, z.number({ required_error: "Contact is required" }).int("Contact must be an integer").min(1_000_000_000, "Contact number must be exactly 10 digits").max(9_999_999_999, "Contact number must be exactly 10 digits")),
  ownerEmail: z.preprocess((val) => {
    return typeof val === "string" && val.trim() !== "" ? val : undefined;
  }, z.string().email("Invalid email address").optional()),
  amenities: z.array(z.string()).optional(),
});

export const residentialPropertyDetailsSchema = z
  .object({
    builtUpArea: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number({ required_error: "Built up area is required" }).min(1, "Built up area must be at least 1")),
    carpetArea: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number({ required_error: "Carpet area is required" }).min(1, "Carpet area must be at least 1")),
    superBuiltUpArea: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number().min(1, "Super built up area must be at least 1").optional()),
    unitOfMeasurement: z.string().optional(),
    flatNumber: z.string().optional(),
    furnishingType: z.string().optional(),
    bathrooms: z.string().optional(),
    balconies: z.string().optional(),
    floorNumber: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number().min(0, "Floor number must be at least 0").optional()),
    totalFloors: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number().min(1, "Total floors must be at least 1").optional()),
    parking: z.string().optional(),
    ageOfProperty: z.string().optional(),
  })
  .merge(commonPropertyDetailsSchema);

export const commercialPropertyDetailsSchema = z
  .object({
    builtUpArea: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number({ required_error: "Built up area is required" }).min(1, "Built up area must be at least 1")),
    carpetArea: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number({ required_error: "Carpet area is required" }).min(1, "Carpet area must be at least 1")),
    pantry: z.string().optional(),
    washroom: z.string().optional(),
    parking: z.string().optional(),
    ageOfProperty: z.string().optional(),
    cabin: z.string().optional(),
    floorNumber: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number().min(0, "Floor number must be at least 0").optional()),
  })
  .merge(commonPropertyDetailsSchema);

export const landPropertyDetailsSchema = z
  .object({
    widthDepth: z.string().optional(),
    roadTouch: z.string().optional(),
    fencing: z.string().optional(),
    titleClear: z.string().optional(),
    ownerName: z.string().min(2, "Owner name is required"),
    ownerContact: z
      .number({ invalid_type_error: "Contact must be a number" })
      .int("Contact must be an integer")
      .min(1_000_000_000, "Contact number must be exactly 10 digits")
      .max(9_999_999_999, "Contact number must be exactly 10 digits"),
  })
  .merge(commonPropertyDetailsSchema);

export const industrialPropertyDetailsSchema = z
  .object({
    waterSupply: z.string().optional(),
    fireNOC: z.string().optional(),
    parking: z.string().optional(),
    loadingArea: z.preprocess((val) => {
      if (typeof val === "string" && val.trim() !== "") {
        const num = Number(val);
        return isNaN(num) ? undefined : num;
      }
      return val;
    }, z.number({ required_error: "Loading Area is required" }).min(1, "Loading Area must be at least 1")),
  })
  .merge(commonPropertyDetailsSchema);

const sellDetailsSchema = z
  .object({
    price: z.preprocess(
      asNumberOrUndef,
      z.number({ required_error: "Price is required" })
    ),
    ownershipType: z
      .string({ required_error: "Ownership type is required" })
      .min(1, "Ownership type is required"),
    brokerageAvailable: z.enum(["yes", "no"]),
    brokerageAmount: z
      .union([
        z.preprocess(
          asNumberOrUndef,
          z.number().min(0, "Brokerage amount must be at least 0")
        ),
        z.undefined(),
      ])
      .optional(),
    availability: z
      .string({ required_error: "Availability is required" })
      .min(1, "Availability is required"),
  })
  // If "no", drop brokerageAmount entirely so it never validates
  .transform((data) =>
    data.brokerageAvailable === "no"
      ? { ...data, brokerageAmount: undefined }
      : data
  )
  .refine(
    (data) =>
      data.brokerageAvailable === "yes"
        ? typeof data.brokerageAmount === "number"
        : true,
    {
      path: ["brokerageAmount"],
      message: "Amount is required when brokerage is available",
    }
  );

const rentDetailsSchema = z
  .object({
    monthlyRent: z.preprocess(
      asNumberOrUndef,
      z.number({ required_error: "Monthly Rent is required" })
    ),
    securityDeposit: z.preprocess(
      asNumberOrUndef,
      z.number({ required_error: "Security Deposit is required" })
    ),
    maintenanceCharges: z.preprocess(
      asNumberOrUndef,
      z.number({ required_error: "Maintenance is required" })
    ),
    brokerageAvailable: z.enum(["yes", "no"]),
    brokerageAmount: z
      .union([
        z.preprocess(
          asNumberOrUndef,
          z.number().min(0, "Brokerage amount must be at least 0")
        ),
        z.undefined(),
      ])
      .optional(),
    lockInPeriod: z
      .string({ required_error: "Lock in period is required" })
      .min(1, "Lock in period is required"),
    leaseDuration: z
      .string({ required_error: "Lease duration is required" })
      .min(1, "Lease duration is required"),
    agreementType: z
      .string({ required_error: "Agreement type is required" })
      .min(1, "Agreement type is required"),
    availableFrom: z.preprocess(
      (val) =>
        typeof val === "string" || val instanceof Date
          ? isNaN(new Date(val).getTime())
            ? undefined
            : new Date(val)
          : undefined,
      z.date({
        required_error: "Available from is required",
        invalid_type_error: "Available from must be a valid date",
      })
    ),
  })
  .transform((data) =>
    data.brokerageAvailable === "no"
      ? { ...data, brokerageAmount: undefined }
      : data
  )
  .refine(
    (data) =>
      data.brokerageAvailable === "yes"
        ? typeof data.brokerageAmount === "number"
        : true,
    {
      path: ["brokerageAmount"],
      message: "Amount is required when brokerage is available",
    }
  );

// Lease Details Schema
const leaseDetailsSchema = z.object({
  monthlyRent: z.preprocess((val) => {
    if (typeof val === "string" && val.trim() !== "") {
      const num = Number(val);
      return isNaN(num) ? undefined : num;
    }
    return val;
  }, z.number({ required_error: "Monthly Rent is required" })),
  securityDeposit: z.preprocess((val) => {
    if (typeof val === "string" && val.trim() !== "") {
      const num = Number(val);
      return isNaN(num) ? undefined : num;
    }
    return val;
  }, z.number({ required_error: "Security Deposit is required" })),
  maintenanceCharges: z.preprocess((val) => {
    if (typeof val === "string" && val.trim() !== "") {
      const num = Number(val);
      return isNaN(num) ? undefined : num;
    }
    return val;
  }, z.number({ required_error: "Maintenance is required" })),
  lockInPeriod: z
    .string({
      required_error: "Lock in period is required",
    })
    .min(1, "Lock in period is required"),
  leaseDuration: z
    .string({
      required_error: "Lease duration is required",
    })
    .min(1, "Lease duration is required"),
  agreementType: z
    .string({
      required_error: "Agreement type is required",
    })
    .min(1, "Agreement type is required"),
});

// Pre-Leased Details Schema
const preLeasedDetailsSchema = z
  .object({
    monthlyRent: z.preprocess((val) => {
      if (typeof val === "string" && val.trim() !== "") {
        const num = Number(val);
        return isNaN(num) ? undefined : num;
      }
      return val;
    }, z.number({ required_error: "Monthly Rent is required" })),
    tenantName: z
      .string({
        required_error: "Tenant name is required",
      })
      .min(1, "Tenant name is required"),
    leaseDuration: z
      .string({
        required_error: "Lease duration is required",
      })
      .min(1, "Lease duration is required"),
    lockInPeriod: z
      .string({
        required_error: "Lock in period is required",
      })
      .min(1, "Lock in period is required"),
    roiPercentage: z.preprocess((val) => {
      return typeof val === "number" && !isNaN(val) ? val : undefined;
    }, z.number({ required_error: "ROI percentage is required" }).min(1, "ROI percentage must be at least 1")),
    leaseStartDate: z.preprocess(
      (val) => {
        if (typeof val === "string" || val instanceof Date) {
          const date = new Date(val);
          return isNaN(date.getTime()) ? undefined : date;
        }
        return undefined;
      },
      z.date({
        required_error: "Lease start date is required",
        invalid_type_error: "Lease start date must be a valid date",
      })
    ),

    leaseEndDate: z.preprocess(
      (val) => {
        if (typeof val === "string" || val instanceof Date) {
          const date = new Date(val);
          return isNaN(date.getTime()) ? undefined : date;
        }
        return undefined;
      },
      z.date({
        required_error: "Lease end date is required",
        invalid_type_error: "Lease end date must be a valid date",
      })
    ),
  })
  .superRefine((data, ctx) => {
    if (data.leaseEndDate < data.leaseStartDate) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        path: ["leaseEndDate"],
        message: "Lease end date cannot be earlier than lease start date",
      });
    }
  });

// Facilities Schema
const facilitiesSchema = z.object({
  amenities: z.array(z.string()).optional(),
  tags: z.array(z.string()).optional(),
  facilities: z.record(z.array(facilityItemSchema)).optional(),
});

// Images Schema
const imagesSchema = z.object({
  media: z.array(z.string()).optional(),
});

export const propertyDefaultValues = {
  // Basic Details
  title: "",
  description: "",
  project: "",
  propertyType: "",
  subcategory: "",
  reraId: "",
  configuration: "",
  listingType: "",

  // Location & Owner
  address: "",
  locality: "",
  city: "",
  pincode: "" as unknown as number,
  landZoneType: "",

  // Property Details (Generic)
  carpetArea: "" as unknown as number,
  builtUpArea: "" as unknown as number,
  superBuiltUpArea: "" as unknown as number,
  bedrooms: "",
  bathrooms: "",
  balconies: "",
  totalFloors: "" as unknown as number,
  floorNumber: "" as unknown as number,
  carParking: "",
  furnishingStatus: "",
  ageOfProperty: "",
  facing: "",
  possessionStatus: "",

  // Common Property Details
  ownerName: "",
  ownerContact: 0 as unknown as number,
  ownerEmail: "",
  amenities: [],

  // Residential Specific
  unitOfMeasurement: "",
  flatNumber: "",
  furnishingType: "",
  parking: "",

  // Commercial Specific
  pantry: "",
  washroom: "",
  cabin: "",

  // Land Specific
  widthDepth: "",
  roadTouch: "",
  fencing: "",
  titleClear: "",

  // Industrial Specific
  waterSupply: "",
  fireNOC: "",
  loadingArea: 0 as unknown as number,

  // Sell Details
  price: "" as unknown as number,
  ownershipType: "",
  brokerageAvailable: "",
  brokerageAmount: undefined,
  availability: "",

  // Rent Details
  monthlyRent: "" as unknown as number,
  securityDeposit: "" as unknown as number,
  maintenanceCharges: "" as unknown as number,
  lockInPeriod: "",
  leaseDuration: "",
  agreementType: "",
  availableFrom: "",

  // Pre-Leased Details
  tenantName: "",
  roiPercentage: "" as unknown as number,
  leaseStartDate: "",
  leaseEndDate: "",

  // Facilities
  tags: [],
  facilities: {},

  // Images/Media
  media: [],
};

export {
  basicDetailsSchema,
  facilitiesSchema,
  imagesSchema,
  leaseDetailsSchema,
  locationOwnerSchema,
  preLeasedDetailsSchema,
  propertyDetailsSchema,
  rentDetailsSchema,
  sellDetailsSchema,
};
