import Joi, { ObjectSchema } from 'joi';

import Country from '@/modules/master/location/country/country.model.js';
import State from './state/state.model.js';
import City from './city/city.model.js';
import Area from './area/area.model.js';

import { objectId } from '@/shared/validations/custom.validation.js';
import { generateJoiValidation } from '@/shared/validations/generateJoiValidation.js';
import { locationType } from '@/shared/constants/enum.constant.js';
import { capitalize } from '@/shared/utils/commonHelper.js';
import {
  validateLookupLocationHierarchy,
  validateCreateLocationHierarchy,
} from './location.hierarchy.validation.js';

type ValidationShape = {
  body?: ObjectSchema;
  params?: ObjectSchema;
  query?: ObjectSchema;
};

const params = Joi.object({
  type: Joi.string()
    .required()
    .valid(...locationType),
  id: Joi.string().custom(objectId).optional(),
});

const query = Joi.object({
  query: Joi.object().keys({
    sortBy: Joi.string(),
    limit: Joi.number().integer().min(1),
    page: Joi.number().integer().min(-1),
    fields: Joi.string(),
    populate: Joi.string(),
    search: Joi.string(),
    state: Joi.string(),
  }),
});

// GeoJSON validation schema
const geoJsonPointSchema = Joi.object({
  type: Joi.string().valid('Point').required(),
  coordinates: Joi.array().items(Joi.number()).length(2).required(),
});

// Custom validation schemas for models with special requirements
const customValidations = {
  country: {
    create: Joi.object({
      name: Joi.string().trim().lowercase().required(),
      loc: geoJsonPointSchema.optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
    update: Joi.object({
      name: Joi.string().trim().lowercase().optional(),
      loc: geoJsonPointSchema.optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
  },
  state: {
    create: Joi.object({
      name: Joi.string().trim().lowercase().required(),
      loc: geoJsonPointSchema.optional(),
      country: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
    update: Joi.object({
      name: Joi.string().trim().lowercase().optional(),
      loc: geoJsonPointSchema.optional(),
      country: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
  },
  city: {
    create: Joi.object({
      name: Joi.string().trim().lowercase().required(),
      loc: geoJsonPointSchema.optional(),
      state: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
    update: Joi.object({
      name: Joi.string().trim().lowercase().optional(),
      loc: geoJsonPointSchema.optional(),
      state: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
    }),
  },
  area: {
    create: Joi.object({
      name: Joi.string().trim().lowercase().required(),
      loc: geoJsonPointSchema.optional(),
      city: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
      pinCode: Joi.array().items(Joi.number()).optional(),
    }),
    update: Joi.object({
      name: Joi.string().trim().lowercase().optional(),
      loc: geoJsonPointSchema.optional(),
      city: Joi.string().custom(objectId).optional(),
      createdBy: Joi.string().custom(objectId).optional(),
      updatedBy: Joi.string().custom(objectId).optional(),
      pinCode: Joi.array().items(Joi.number()).optional(),
    }),
  },
};

const locationSchemas = {
  country: Country,
  state: State,
  city: City,
  area: Area,
};

export const validate: Record<string, ValidationShape> = {};

Object.entries(locationSchemas).forEach(([key, model]) => {
  const capitalKey = capitalize(key);
  const schema = model.schema;

  // Check if we have custom validation for this model
  const customValidation = customValidations[key];
  
  validate[`create${capitalKey}`] = {
    body: customValidation?.create || generateJoiValidation(schema),
  };

  validate[`update${capitalKey}`] = {
    params,
    body: customValidation?.update || generateJoiValidation(schema, true),
  };

  validate[`get${capitalKey}`] = {
    params,
    query,
  };

  validate[`delete${capitalKey}`] = {
    params,
  };
});

validate.lookupLocationHierarchy = validateLookupLocationHierarchy;
validate.createLocationHierarchy = validateCreateLocationHierarchy;

// Add place_id validation schemas
const placeIdBody = Joi.object({
  placeId: Joi.string().required()
});

validate.createFromPlaceId = {
  body: placeIdBody,
};

validate.validatePlaceId = {
  body: placeIdBody,
};