import { ApiError } from '@/shared/utils/errors';
import {
  IPropertyFilter,
  IsWebsiteCreated,
  IWebSiteBuilderDoc,
  UpdateWebSiteBuilder,
} from './makanifySites.interface';
import { MakanifySites } from './makanifySites.model';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { ICompanyDoc } from '../company/company.interface';
import { ITeamDoc } from '../teams/teams.interface';
import { bannedMakanifySites } from './makanifySites.constants';
import mongoose, { FilterQuery, FlattenMaps } from 'mongoose';
import {
  getPropertyLocationCount,
  queryPrimaryProperties,
} from '../individualProperties/individualProperties.service';
import {
  avgPriceOptions,
  getPropertyLocationCountResponse,
  IPropertyDoc,
  PropertyAgeOptions,
  SqFtOptions,
} from '../individualProperties/individualProperties.interface';
import { QueryResult } from '@/shared/utils/plugins/paginate/paginate';
import { propertyTypeOptions } from '../individualProperties/individualProperties.utils';
import { list as categoryList } from '../master/property/category/category.service';
import { list as SubCategoryList } from '../master/property/subCategory/subCategory.service';
import { list as ConfigurationList } from '../master/property/configuration/configuration.service';
import { getObjectId } from '@/shared/utils/commonHelper';
import { makeOptionsList } from './makanifySites.utils';
import { Company } from '../company/company.model';
import config from '@/shared/config/config';

const { MakanifySitesResponseCodes } = responseCodes;
export const createSite = async (
  data: UpdateWebSiteBuilder,
): Promise<IWebSiteBuilderDoc> => {
  const { subdomainName } = data;

  // Block reserved subdomains
  const reservedSubdomains =
    config?.websiteBuilderReservedSubdomain
      ?.split(',')
      .map((s) => s.trim().toLowerCase()) || [];

  if (subdomainName && reservedSubdomains.includes(subdomainName.toLowerCase()))
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      `Subdomain "${subdomainName}" is reserved and cannot be used.`,
      true,
      '',
      MakanifySitesResponseCodes.SUBDOMAIN_RESERVED,
    );

  let site: IWebSiteBuilderDoc;
  if (data?.id) {
    site = await MakanifySites.findById(data.id);
    if (!site)
      throw new ApiError(
        defaultStatus.OK,
        'Site not found',
        true,
        '',
        MakanifySitesResponseCodes.MakanifySites_NOT_FOUND,
      );
    site = await MakanifySites.findByIdAndUpdate(data.id, data);
    site.save();
    return site;
  }
  site = await MakanifySites.create(data);
  return site;
};

export const fetchSite = async (
  subdomainId: string,
): Promise<FlattenMaps<IWebSiteBuilderDoc>> => {
  let site: FlattenMaps<IWebSiteBuilderDoc>;
  if (subdomainId) {
    site = await MakanifySites.findOne({
      _id: subdomainId,
    })
      .populate<ICompanyDoc>('company', ['name', 'status'])
      .populate<ITeamDoc>('teamId');
    site = site.toJSON();
    if (!site)
      throw new ApiError(
        defaultStatus.OK,
        'Site not found',
        true,
        '',
        MakanifySitesResponseCodes.MAKANIFYSITES_NOT_FOUND,
      );

    return site;
  }
  return site;
};

export const isSiteCreated = async (
  subdomain: string,
): Promise<IsWebsiteCreated> => {
  let site: IWebSiteBuilderDoc;
  if (bannedMakanifySites.includes(subdomain.toLowerCase()) || !subdomain)
    return { isWebsiteCreated: false };
  if (subdomain) {
    site = await MakanifySites.findOne({ subdomain });
    if (!site)
      throw new ApiError(
        defaultStatus.OK,
        'Site not found',
        true,
        '',
        MakanifySitesResponseCodes.DOMAIN_NOT_AVAILABLE,
      );
    return {
      isWebsiteCreated: true,
    };
  }
  return { isWebsiteCreated: false };
};

export const fetchHomepage = async (
  subdomainId: string,
): Promise<{
  site: FlattenMaps<IWebSiteBuilderDoc & { color: string }>;
  popularProperty: QueryResult<IPropertyDoc>;
  listingCount: getPropertyLocationCountResponse;
  propertyTypeOptions: { label: string; value: string }[];
}> => {
  let site: FlattenMaps<IWebSiteBuilderDoc & { color: string }>;
  let popularProperty: QueryResult<IPropertyDoc>;
  let listingCount: getPropertyLocationCountResponse;
  if (subdomainId) {
    site = await MakanifySites.findOne({
      _id: subdomainId,
    });
    const companyInfo = await Company.findOne({ _id: site.company });

    const filter = {
      companyId: getObjectId(site.company),
    };
    const options = {
      populate:
        'locality:name;city:name;configuration:name;project:projectName',
      fields:
        'id,title,description,propertyType,listingType,price,builtUpArea,monthlyRent,carpetArea,bedrooms,bathrooms,locality,city,ownerName,possessionStatus,status,configuration,mediaUrls,project,createdBy,createdAt',
    };
    const listings = await queryPrimaryProperties(filter, options);
    listingCount = await getPropertyLocationCount();
    site = site.toJSON();
    site.color = companyInfo?.color || '#EE5A29';
    if (!site)
      throw new ApiError(
        defaultStatus.OK,
        'Site not found',
        true,
        '',
        MakanifySitesResponseCodes.MAKANIFYSITES_NOT_FOUND,
      );

    return {
      site,
      popularProperty: listings,
      listingCount,
      propertyTypeOptions,
    };
  }
  return { site, popularProperty, listingCount, propertyTypeOptions };
};
export const fetchListings = async (
  filter: FilterQuery<IPropertyDoc>,
  options: Record<string, unknown>,
): Promise<{
  listings: QueryResult<IPropertyDoc>;
}> => {
  const objectIdFields = [
    'propertyType',
    'subcategory',
    'configuration',
    'listingType',
    'id',
  ];

  for (const key of objectIdFields)
    if (filter[key] && mongoose.Types.ObjectId.isValid(filter[key]))
      filter[key] = getObjectId(filter[key]);

  filter = Object.entries(filter)
    .filter(([, v]) => v !== null && v !== '')
    .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});

  const listings = await queryPrimaryProperties(filter, options);

  return { listings };
};

export const fetchFilters = async ({
  categoryId,
  subCategoryId,
}): Promise<IPropertyFilter> => {
  const subcategoryParams: Record<string, string> = {};
  if (categoryId) subcategoryParams.categoryId = categoryId;

  // Prepare params for configuration
  const configurationParams: Record<string, unknown> = {};
  if (categoryId) configurationParams.categoryId = getObjectId(categoryId);
  if (subCategoryId)
    configurationParams.subcategoryId = getObjectId(subCategoryId);

  const category = await categoryList({});
  const subCategoryList = await SubCategoryList(subcategoryParams);
  const configurations = await ConfigurationList(subcategoryParams);
  return {
    category: makeOptionsList(category, 'name', '_id'),
    subcategory: makeOptionsList(subCategoryList, 'name', '_id'),
    configuration: makeOptionsList(configurations, 'name', '_id'),
    buyingType: propertyTypeOptions,
    propertyAge: PropertyAgeOptions,
    avgPrice: avgPriceOptions,
    SqFtOptions: SqFtOptions,
  };
};
