import httpStatus from 'http-status';
import { FilterQuery } from 'mongoose';

import Source from '@/modules/master/constructionStatus/source/source.model';
import ApiError from '@/shared/utils/errors/ApiError';
import {
  IConstructionFilter,
  ISource,
} from '@/modules/master/constructionStatus/constructionStatus.interfaces';
import { PaginateOptions } from '@/shared/utils/plugins/paginate/paginate';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';
import { IPaginateResult } from '@/shared/interfaces/model.interface';
const { SourceResponseCodes } = responseCodes;

export const create = async (body: ISource): Promise<ISource> => {
  const { name, company } = body;

  const existing = await Source.findOne({
    name: name,
    company: company,
  });

  if (existing)
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'Source with this name already exists.',
      true,
      '',
      SourceResponseCodes.SOURCE_ALREADY_EXISTS,
    );

  return await Source.create(body);
};

export const getById = async (id: string): Promise<ISource> => {
  const source = await Source.findById(id);
  if (!source) throw new ApiError(httpStatus.NOT_FOUND, 'Source not found');
  return source;
};

export const update = async (
  id: string,
  body: Partial<ISource>,
): Promise<ISource> => {
  const source = await Source.findByIdAndUpdate(id, body, {
    new: true,
    runValidators: true,
  });
  if (!source) throw new ApiError(httpStatus.NOT_FOUND, 'Source not found');
  return source;
};

export const remove = async (id: string): Promise<boolean> => {
  await safeDeleteById(Source, id, SourceResponseCodes.SOURCE_IN_USE);
  return true;
};

export const list = (query: Record<string, unknown>): Promise<ISource[]> =>
  Source.find(query);

export const querySource = async (
  filter: IConstructionFilter = {},
  options: PaginateOptions = {},
): Promise<IPaginateResult<ISource>> => {
  const { search, ...restFilter } = filter;
  let queryFilter: FilterQuery<ISource> = {
    ...restFilter,
  };

  if (search) queryFilter.$or = [{ name: { $regex: search, $options: 'i' } }];

  return await Source.paginate(queryFilter, options);
};

export const cloneDefaultLeadSourceForCompany = async (
  companyId: string,
  createdBy?: string,
) => {
  const defaultLeadSources = await Source.find({ isDefault: true });

  if (!defaultLeadSources.length) return;

  // Deduplicate by name (case-insensitive + trimmed)
  const uniqueNames = new Set<string>();
  const newSources = [];

  for (const src of defaultLeadSources) {
    const name = src.name.trim().toLowerCase();

    if (!uniqueNames.has(name)) {
      uniqueNames.add(name);

      newSources.push({
        name: src.name.trim(),
        company: companyId,
        isDefault: true,
        createdBy,
        updatedBy: createdBy,
      });
    }
  }

  if (newSources.length) await Source.insertMany(newSources);
};
