import Joi, { AnySchema } from 'joi';
import { objectId } from '@/shared/validations/custom.validation.js';
import { LeadRoutingType } from '@/modules/makanifySites/makanifySites.interface';

type MongoosePath = {
  instance: string;
  options?: {
    ref?: string;
  };
  isRequired?: boolean | (() => boolean);
  enumValues?: unknown[];
};

type MongooseSchemaLike = {
  paths: {
    [key: string]: MongoosePath;
  };
};

const mongooseToJoiTypeMap: Record<string, AnySchema> = {
  String: Joi.string(),
  Number: Joi.number(),
  Boolean: Joi.boolean(),
  Date: Joi.date(),
  ObjectId: Joi.string().custom(objectId),
  Array: Joi.array().items(Joi.string()),
};

/**
 * Helper to generate Joi type for a MongoosePath
 */
const generateJoiForPath = (path: MongoosePath, isUpdate: boolean): AnySchema => {
  let joiType = mongooseToJoiTypeMap[path.instance] || Joi.any();

  if (path.options?.ref) joiType = Joi.string().custom(objectId);

  if (path.instance === 'Array' && path.options?.ref) joiType = Joi.array().items(Joi.string().custom(objectId));

  if (path.enumValues?.length) joiType = joiType.valid(...path.enumValues);

  const isRequired = typeof path.isRequired === 'function' ? path.isRequired() : path.isRequired;

  joiType = isUpdate ? joiType.optional() : isRequired ? joiType.required() : joiType.optional();

  return joiType;
};

/**
 * Generate Joi validation schema from Mongoose schema paths recursively
 * Handles nested paths like "phone.dialCode"
 * @param paths - The mongoose schema paths
 * @param isUpdate - Whether validation is for update operation
 * @returns Joi schema object
 */
const buildJoiSchema = (paths: Record<string, MongoosePath>, isUpdate: boolean): Record<string, AnySchema> => {
  const schemaTree: Record<string, AnySchema> = {};

  // Group keys by first segment (rootKey)
  const grouped: Record<string, Record<string, MongoosePath>> = {};

  Object.entries(paths).forEach(([fullKey, path]) => {
    const [rootKey, ...rest] = fullKey.split('.');

    if (rest.length === 0) {
      // top-level key
      grouped[rootKey] = grouped[rootKey] || {};
      grouped[rootKey][rootKey] = path;
    } else {
      // nested key
      grouped[rootKey] = grouped[rootKey] || {};
      grouped[rootKey][rest.join('.')] = path;
    }
  });

  // Now build Joi schema for each rootKey
  Object.entries(grouped).forEach(([rootKey, subPaths]) => {
    if (Object.keys(subPaths).length === 1 && subPaths[rootKey])
      // Single top-level path (no nesting)
      schemaTree[rootKey] = generateJoiForPath(subPaths[rootKey], isUpdate);
    else
      // Nested object - recurse
      schemaTree[rootKey] = Joi.object(buildJoiSchema(subPaths, isUpdate));
  });

  return schemaTree;
};

export const generateJoiValidation = (mongooseSchema: MongooseSchemaLike, isUpdate = false): Joi.ObjectSchema => {
  const joiSchema = buildJoiSchema(mongooseSchema.paths, isUpdate);

  // Add custom optional global fields
  joiSchema.longitude = Joi.number().optional();
  joiSchema.latitude = Joi.number().optional();

  return Joi.object(joiSchema);
};

export const withLeadRoutingConditionalFields = (
  baseSchema: Joi.ObjectSchema,
): Joi.ObjectSchema =>
  baseSchema.keys({
    id: Joi.string().optional().custom(objectId),
    userId: Joi.when('leadRoutingType', {
      is: LeadRoutingType.USER,
      then: Joi.string().custom(objectId).required(),
      otherwise: Joi.forbidden(),
    }),
    teamId: Joi.when('leadRoutingType', {
      is: LeadRoutingType.TEAM,
      then: Joi.string().custom(objectId).required(),
      otherwise: Joi.forbidden(),
    }),
  });

export const isSiteCreatedFields = () =>
  Joi.object().keys({ subdomains: Joi.string().required() });
