import { z } from 'zod';

export interface UserData {
  id?: string;
  firstname: string;
  lastname: string;
  email: string;
  phoneNumber?: string;
  description?: string;
  companyName?: string;
  companyOverview?: string;
  companyWebsite?: string;
  companyLocation?: string;
  offeredServices?: string;
  areasServed?: string[];
  hasProfile?: boolean;
  hasCompanyLogo?: boolean;
  licensedIn?: string[];
  gender?: 'male' | 'female';
  customerType?: 'buyer' | 'seller' | 'professional';
  customerSubType?: 'broker' | 'cpa' | 'attorney' | 'titleCompany' | 'surveyor' | 'appraiser';
  created?: Date;
  updated?: Date;
}
export type SortByOptions = 'priceAsc' | 'priceDesc' | 'creationDateFirst' | 'creationDateLast' | 'nameAsc' | 'nameDesc' | 'srAsc' | 'srDesc' | 'cfAsc' | 'cfDesc';
export type SortByTypes = 'professional' | 'listing' | 'business' | 'commercial';
export type Gender = 'male' | 'female';
export type CustomerType = 'buyer' | 'seller' | 'professional';
export type CustomerSubType = 'broker' | 'cpa' | 'attorney' | 'titleCompany' | 'surveyor' | 'appraiser';
export type ListingsCategory = 'commercialProperty' | 'business';

export const GenderEnum = z.enum(['male', 'female']);
export const CustomerTypeEnum = z.enum(['buyer', 'seller', 'professional']);
export const SubscriptionTypeEnum = z.enum(['free', 'professional', 'broker']);
export const CustomerSubTypeEnum = z.enum(['broker', 'cpa', 'attorney', 'titleCompany', 'surveyor', 'appraiser']);
export const ListingsCategoryEnum = z.enum(['commercialProperty', 'business']);
export const ShareCategoryEnum = z.enum(['commercialProperty', 'business', 'user']);
export const ZodEventTypeEnum = z.enum(['view', 'print', 'email', 'facebook', 'x', 'linkedin', 'contact', 'favorite', 'emailus', 'pricing']);
export type EventTypeEnum = z.infer<typeof ZodEventTypeEnum>;
const PropertyTypeEnum = z.enum(['retail', 'land', 'industrial', 'office', 'mixedUse', 'multifamily', 'uncategorized']);
const TypeEnum = z.enum([
  'automotive',
  'industrialServices',
  'foodAndRestaurant',
  'realEstate',
  'retail',
  'oilfield',
  'service',
  'advertising',
  'agriculture',
  'franchise',
  'professional',
  'manufacturing',
  'uncategorized',
]);

const USStates = z.enum([
  'AL',
  'AK',
  'AZ',
  'AR',
  'CA',
  'CO',
  'CT',
  'DC',
  'DE',
  'FL',
  'GA',
  'HI',
  'ID',
  'IL',
  'IN',
  'IA',
  'KS',
  'KY',
  'LA',
  'ME',
  'MD',
  'MA',
  'MI',
  'MN',
  'MS',
  'MO',
  'MT',
  'NE',
  'NV',
  'NH',
  'NJ',
  'NM',
  'NY',
  'NC',
  'ND',
  'OH',
  'OK',
  'OR',
  'PA',
  'RI',
  'SC',
  'SD',
  'TN',
  'TX',
  'UT',
  'VT',
  'VA',
  'WA',
  'WV',
  'WI',
  'WY',
]);
export const AreasServedSchema = z.object({
  county: z.string().optional().nullable(),
  state: z
    .string()
    .nullable()
    .refine(val => val !== null && val !== '', {
      message: 'State is required',
    }),
});

export const LicensedInSchema = z.object({
  state: z
    .string()
    .nullable()
    .refine(val => val !== null && val !== '', {
      message: 'State is required',
    }),
  registerNo: z.string().nonempty('License number is required'),
});
export const GeoSchema = z
  .object({
    name: z.string().optional().nullable(),
    state: z.string().refine(val => USStates.safeParse(val).success, {
      message: 'Invalid state. Must be a valid 2-letter US state code.',
    }),
    latitude: z.number().refine(
      value => {
        return value >= -90 && value <= 90;
      },
      {
        message: 'Latitude muss zwischen -90 und 90 liegen',
      },
    ),
    longitude: z.number().refine(
      value => {
        return value >= -180 && value <= 180;
      },
      {
        message: 'Longitude muss zwischen -180 und 180 liegen',
      },
    ),
    county: z.string().optional().nullable(),
    housenumber: z.string().optional().nullable(),
    street: z.string().optional().nullable(),
    zipCode: z.number().optional().nullable(),
  })
  .superRefine((data, ctx) => {
    if (!data.state) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'You need to select at least a state',
        path: ['name'],
      });
    }
  });
const phoneRegex = /^(\+1|1)?[-.\s]?\(?[2-9]\d{2}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/;
export const UserSchema = z
  .object({
    id: z.string().uuid().optional().nullable(),
    firstname: z.string().min(3, { message: 'First name must contain at least 2 characters' }),
    lastname: z.string().min(3, { message: 'Last name must contain at least 2 characters' }),
    email: z.string().email({ message: 'Invalid email address' }),
    phoneNumber: z.string().optional().nullable(),
    description: z.string().optional().nullable(),
    companyName: z.string().optional().nullable(),
    companyOverview: z.string().optional().nullable(),
    companyWebsite: z.string().url({ message: 'Invalid URL format' }).optional().nullable(),
    location: GeoSchema.optional().nullable(),
    offeredServices: z.string().optional().nullable(),
    areasServed: z.array(AreasServedSchema).optional().nullable(),
    hasProfile: z.boolean().optional().nullable(),
    hasCompanyLogo: z.boolean().optional().nullable(),
    licensedIn: z.array(LicensedInSchema).optional().nullable(),
    gender: GenderEnum.optional().nullable(),
    customerType: CustomerTypeEnum,
    customerSubType: CustomerSubTypeEnum.optional().nullable(),
    created: z.date().optional().nullable(),
    updated: z.date().optional().nullable(),
    subscriptionId: z.string().optional().nullable(),
    subscriptionPlan: SubscriptionTypeEnum.optional().nullable(),
    favoritesForUser: z.array(z.string()),
    showInDirectory: z.boolean(),
  })
  .superRefine((data, ctx) => {
    if (data.customerType === 'professional') {
      if (!data.customerSubType) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Customer subtype is required for professional customers',
          path: ['customerSubType'],
        });
      }
      if (!data.companyName || data.companyName.length < 6) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Company Name must contain at least 6 characters for professional customers',
          path: ['companyName'],
        });
      }
      if (!data.phoneNumber || !phoneRegex.test(data.phoneNumber)) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Phone number is required and must be in US format (XXX) XXX-XXXX for professional customers',
          path: ['phoneNumber'],
        });
      }

      if (!data.companyOverview || data.companyOverview.length < 10) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Company overview must contain at least 10 characters for professional customers',
          path: ['companyOverview'],
        });
      }

      if (!data.description || data.description.length < 10) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Description must contain at least 10 characters for professional customers',
          path: ['description'],
        });
      }

      if (!data.offeredServices || data.offeredServices.length < 10) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Offered services must contain at least 10 characters for professional customers',
          path: ['offeredServices'],
        });
      }

      if (!data.location) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'Company location is required for professional customers',
          path: ['location'],
        });
      }

      if (!data.areasServed || data.areasServed.length < 1) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: 'At least one area served is required for professional customers',
          path: ['areasServed'],
        });
      }
    }
  });

export type AreasServed = z.infer<typeof AreasServedSchema>;
export type LicensedIn = z.infer<typeof LicensedInSchema>;
export type User = z.infer<typeof UserSchema>;

export const BusinessListingSchema = z
  .object({
    id: z.string().uuid().optional().nullable(),
    email: z.string().email(),
    type: z.string().refine(val => TypeEnum.safeParse(val).success, {
      message: 'Invalid type. Must be one of: ' + TypeEnum.options.join(', '),
    }),
    title: z.string().min(10),
    description: z.string().min(10),
    location: GeoSchema,
    price: z.number().positive().optional().nullable(),
    favoritesForUser: z.array(z.string()),
    draft: z.boolean(),
    listingsCategory: ListingsCategoryEnum,
    realEstateIncluded: z.boolean().optional().nullable(),
    leasedLocation: z.boolean().optional().nullable(),
    franchiseResale: z.boolean().optional().nullable(),
    salesRevenue: z.number().positive().nullable(),
    cashFlow: z.number().optional().nullable(),
    ffe: z.number().optional().nullable(),
    inventory: z.number().optional().nullable(),
    supportAndTraining: z.string().min(5).optional().nullable(),
    employees: z.number().int().positive().max(100000).optional().nullable(),
    established: z.number().int().min(1).max(250).optional().nullable(),
    internalListingNumber: z.number().int().positive().optional().nullable(),
    reasonForSale: z.string().min(5).optional().nullable(),
    brokerLicencing: z.string().optional().nullable(),
    internals: z.string().min(5).optional().nullable(),
    imageName: z.string().optional().nullable(),
    slug: z.string().optional().nullable(),
    created: z.date(),
    updated: z.date(),
  })
  .superRefine((data, ctx) => {
    if (data.price && data.price > 1000000000) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'Price must less than or equal $1,000,000,000',
        path: ['price'],
      });
    }
    if (data.salesRevenue && data.salesRevenue > 100000000) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'SalesRevenue must less than or equal $100,000,000',
        path: ['salesRevenue'],
      });
    }
    if (data.cashFlow && data.cashFlow > 100000000) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'CashFlow must less than or equal $100,000,000',
        path: ['cashFlow'],
      });
    }
  });
export type BusinessListing = z.infer<typeof BusinessListingSchema>;

export const CommercialPropertyListingSchema = z
  .object({
    id: z.string().uuid().optional().nullable(),
    serialId: z.number().int().positive().optional().nullable(),
    email: z.string().email(),
    type: z.string().refine(val => PropertyTypeEnum.safeParse(val).success, {
      message: 'Invalid type. Must be one of: ' + PropertyTypeEnum.options.join(', '),
    }),
    title: z.string().min(10),
    description: z.string().min(10),
    location: GeoSchema,
    price: z.number().positive().optional().nullable(),
    favoritesForUser: z.array(z.string()),
    listingsCategory: ListingsCategoryEnum,
    internalListingNumber: z.number().int().positive().optional().nullable(),
    draft: z.boolean(),
    imageOrder: z.array(z.string()),
    imagePath: z.string().nullable().optional(),
    slug: z.string().optional().nullable(),
    created: z.date(),
    updated: z.date(),
  })
  .superRefine((data, ctx) => {
    if (data.price && data.price > 1000000000) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message: 'Price must less than or equal $1,000,000,000',
        path: ['price'],
      });
    }
  });

export type CommercialPropertyListing = z.infer<typeof CommercialPropertyListingSchema>;

export const SenderSchema = z.object({
  name: z.string().min(6, { message: 'Name must be at least 6 characters long' }),
  email: z.string().email({ message: 'Invalid email address' }),
  phoneNumber: z.string().regex(/^(\+1|1)?[-.\s]?\(?[2-9]\d{2}\)?[-.\s]?\d{3}[-.\s]?\d{4}$/, {
    message: 'Invalid US phone number format',
  }),
  state: z.string().refine(val => USStates.safeParse(val).success, {
    message: 'Invalid state. Must be a valid 2-letter US state code.',
  }),
  comments: z.string().min(10, { message: 'Comments must be at least 10 characters long' }),
});
export type Sender = z.infer<typeof SenderSchema>;
export const ShareByEMailSchema = z.object({
  yourName: z.string().min(6, { message: 'Name must be at least 6 characters long' }),
  recipientEmail: z.string().email({ message: 'Invalid email address' }),
  yourEmail: z.string().email({ message: 'Invalid email address' }),
  listingTitle: z.string().optional().nullable(),
  url: z.string().url({ message: 'Invalid URL format' }).optional().nullable(),
  id: z.string().optional().nullable(),
  type: ShareCategoryEnum,
});
export type ShareByEMail = z.infer<typeof ShareByEMailSchema>;

export const ListingEventSchema = z.object({
  id: z.string().uuid(), // UUID für das Event
  listingId: z.string().uuid().optional().nullable(), // UUID für das Listing
  email: z.string().email().optional().nullable(), // EMail des den Benutzer, optional, wenn kein Benutzer eingeloggt ist
  eventType: ZodEventTypeEnum, // Die Event-Typen
  eventTimestamp: z.string().datetime().or(z.date()), // Der Zeitstempel des Events, kann ein String im ISO-Format oder ein Date-Objekt sein
  userIp: z.string().max(45).optional().nullable(), // IP-Adresse des Benutzers, optional
  userAgent: z.string().max(255).optional().nullable(), // User-Agent des Benutzers, optional
  locationCountry: z.string().max(100).optional().nullable(), // Land, optional
  locationCity: z.string().max(100).optional().nullable(), // Stadt, optional
  locationLat: z.string().max(20).optional().nullable(), // Latitude, als String
  locationLng: z.string().max(20).optional().nullable(), // Longitude, als String
  referrer: z.string().max(255).optional().nullable(), // Referrer URL, optional
  additionalData: z.record(z.string(), z.any()).optional().nullable(), // JSON für zusätzliche Daten, z.B. soziale Medien, optional
});
export type ListingEvent = z.infer<typeof ListingEventSchema>;
