import { parseSafeIds } from '@/shared/utils/commonHelper';
import mongoose from 'mongoose';

export const basicInfoKeys = [
  'title',
  'description',
  'propertyType',
  'subcategory',
  'listingType',
  'status',
  'reraId',
  'project',
  'propertyTags',
  'companyId',
];
export const specificationsKeys = [
  'configuration',
  'carpetArea',
  'builtUpArea',
  'superBuiltUpArea',
  'length',
  'width',
  'bedrooms',
  'bathrooms',
  'balconies',
  'totalFloors',
  'floorNumber',
  'carParking',
  'furnishingType',
  'ageOfProperty',
  'possessionStatus',
  'facing',
  'category',
  'pantry',
  'parking',
  'washroom',
  'cabin',
];

export const locationKeys = [
  'address',
  'locality',
  'city',
  'pincode',
  'latitude',
  'longitude',
  'distance',
];

export const ownerKeys = ['ownerName', 'ownerContact', 'ownerEmail'];
export const extrasKeys = ['amenities', 'tags', 'mediaUrls', 'facilities'];
export const sellKeys = [
  'price',
  'totalPrice',
  'ownershipType',
  'brokerageAvailable',
  'brokerageAmount',
  'availability',
  'monthlyRent',
];
export const rentKeys = [
  'monthlyRent',
  'securityDeposit',
  'maintenanceCharges',
  'lockInPeriod',
  'leaseDuration',
  'agreementType',
  'availableFrom',
];
export const preLeaseKeys = [
  'tenantName',
  'roiPercentage',
  'leaseStartDate',
  'leaseEndDate',
];
export const auditKeys = ['createdBy', 'updatedBy', 'createdAt', 'updatedAt'];

export function groupFields<T extends object, K extends keyof T>(
  obj: T,
  keys: K[],
): Pick<T, K> {
  return keys.reduce(
    (acc, key) => {
      if (obj[key] !== undefined) acc[key] = obj[key];

      return acc;
    },
    {} as Pick<T, K>,
  );
}

export function buildProjectFromFields(fields: string): Record<string, 1 | 0> {
  const project: Record<string, 1 | 0> = {};
  fields.split(' ').forEach((field) => {
    project[field] = 1;
  });
  return project;
}

export const setDefaultOptions = (options: Record<string, unknown>) => {
  if (!options.populate)
    options.populate = 'locality:name;city:name;propertyType:name';

  if (!options.fields)
    options.fields =
      'id title description propertyType listingType price monthlyRent securityDeposit carpetArea bedrooms bathrooms locality city ownerName possessionStatus status createdBy createdAt isSharing project';
};

export const buildPriceRangeFilter = (priceRange: string): object => {
  switch (priceRange) {
    case 'under_50L':
      return {
        $or: [{ price: { $lt: 5000000 } }, { monthlyRent: { $lt: 5000000 } }],
      };
    case '50L_1Cr':
      return {
        $or: [
          { price: { $gte: 5000000, $lte: 10000000 } },
          { monthlyRent: { $gte: 5000000, $lte: 10000000 } },
        ],
      };
    case 'above_1Cr':
      return {
        $or: [{ price: { $gt: 10000000 } }, { monthlyRent: { $gt: 10000000 } }],
      };
    default:
      return {};
  }
};

export const buildCarpetAreaFilter = (priceRange: string): object => {
  switch (priceRange) {
    case '100-150':
      return { carpetArea: { $gte: 100, $lte: 150 } };

    case '350-450':
      return { carpetArea: { $gte: 350, $lte: 450 } };

    case '750':
      return { carpetArea: { $gte: 750 } };

    default:
      return {};
  }
};

export const processFilter = (
  filter: Record<string, unknown>,
): Record<string, unknown> => {
  const updatedFilter = { ...filter };

  delete updatedFilter.search;

  // Map propertySubtype to subcategory
  if (updatedFilter.propertySubtype) {
    updatedFilter.subcategory = updatedFilter.propertySubtype;
    delete updatedFilter.propertySubtype;
  }

  if (updatedFilter.furnishingType) {
  const arr = (updatedFilter.furnishingType as string)
    .split(',')
    .map((v) => v.trim())
    .filter(Boolean);

  delete updatedFilter.furnishingType;

  if (!Array.isArray(updatedFilter.$and)) updatedFilter.$and = [];

  updatedFilter.$and.push({
    furnishingType:
      arr.length === 1
        ? { $regex: arr[0], $options: 'i' }
        : { $in: arr.map((v) => new RegExp(v, 'i')) },
  });
}

  if (updatedFilter.minPrice && updatedFilter.maxPrice) {
    const { minPrice, maxPrice } = updatedFilter;
    delete updatedFilter.minPrice;
    delete updatedFilter.maxPrice;

    if (!Array.isArray(updatedFilter.$and)) updatedFilter.$and = [];

    const priceFilter = {
      $or: [
        { price: { $gte: minPrice, $lte: maxPrice } },
        { monthlyRent: { $gte: minPrice, $lte: maxPrice } },
      ],
    };
    (updatedFilter.$and as object[]).push(priceFilter);
  }
  if (updatedFilter.carpetArea) {
    const carpetArea = updatedFilter.carpetArea as string;
    delete updatedFilter.carpetArea;

    if (!Array.isArray(updatedFilter.$and)) updatedFilter.$and = [];

    const carpetAreaFilter = buildCarpetAreaFilter(carpetArea);
    if (Object.keys(carpetAreaFilter).length > 0)
      (updatedFilter.$and as object[]).push(carpetAreaFilter);
  }

  // Convert ObjectId fields
  const objectIdFields = [
    'companyId',
    'propertyType',
    'subcategory',
    'project',
    'city',
    'locality',
    'configuration',
    'createdBy',
  ];

  objectIdFields.forEach((field) => {
    const parsed = parseSafeIds(updatedFilter[field] as string);
    if (parsed) {
      updatedFilter[field] = parsed;
    } else {
      delete updatedFilter[field];
    }
  });

  if (updatedFilter.listingType) {
    const arr = (updatedFilter.listingType as string)
      .split(',')
      .map((v) => v.trim())
      .filter(Boolean);

    updatedFilter.listingType = arr.length === 1 ? arr[0] : { $in: arr };
  }

  return updatedFilter;
};

export const createLookupStages = () => [
  {
    $lookup: {
      from: 'areas',
      localField: 'locality',
      foreignField: '_id',
      as: 'localityData',
    },
  },
  {
    $lookup: {
      from: 'users',
      localField: 'createdBy',
      foreignField: '_id',
      as: 'createdByData',
    },
  },
  {
    $lookup: {
      from: 'cities',
      localField: 'city',
      foreignField: '_id',
      as: 'cityData',
    },
  },
  {
    $lookup: {
      from: 'categories',
      localField: 'propertyType',
      foreignField: '_id',
      as: 'propertyTypeData',
    },
  },
  {
    $lookup: {
      from: 'projects',
      localField: 'project',
      foreignField: '_id',
      as: 'projectData',
    },
  },
];

export const buildSearchMatchConditions = (searchValue: string) => {
  const searchRegex = { $regex: searchValue, $options: 'i' };

  const conditions = [
    { title: searchRegex },
    { ownerName: searchRegex },
    { carpetArea: searchRegex },
    { 'localityData.name': searchRegex },
    { 'cityData.name': searchRegex },
    { 'propertyTypeData.name': searchRegex },
    { 'projectData.projectName': searchRegex },
    {
      $expr: {
        $regexMatch: {
          input: { $toString: '$price' },
          regex: searchValue,
          options: 'i',
        },
      },
    },
    {
      $expr: {
        $regexMatch: {
          input: { $toString: '$monthlyRent' },
          regex: searchValue,
          options: 'i',
        },
      },
    },
  ];

  return conditions;
};

export const createAddFieldsStage = () => ({
  $addFields: {
    'locality.name': { $arrayElemAt: ['$localityData.name', 0] },
    'city.name': { $arrayElemAt: ['$cityData.name', 0] },
    'propertyType.name': { $arrayElemAt: ['$propertyTypeData.name', 0] },
    createdBy: {
      firstName: { $arrayElemAt: ['$createdByData.firstName', 0] },
      lastName: { $arrayElemAt: ['$createdByData.lastName', 0] },
      email: { $arrayElemAt: ['$createdByData.email', 0] },
      _id: { $arrayElemAt: ['$createdByData._id', 0] },
    },
    'project.projectName': { $arrayElemAt: ['$projectData.projectName', 0] },
  },
});

export const buildSearchPipeline = (
  processedFilter: Record<string, unknown>,
  searchValue: string,
  fields: string,
) => {
  return [
    { $match: processedFilter },
    ...createLookupStages(),
    {
      $match: {
        $or: buildSearchMatchConditions(searchValue),
      },
    },
    createAddFieldsStage(),
    {
      $project: buildProjectFromFields(fields),
    },
  ];
};

export const fieldGroups = {
  basicInfo: basicInfoKeys,
  specifications: specificationsKeys,
  location: locationKeys,
  owner: ownerKeys,
  extras: extrasKeys,
  sellDetails: sellKeys,
  rentDetails: rentKeys,
  preLeasedDetails: preLeaseKeys,
  audit: auditKeys,
};
