import { CampaignsRepository } from "@/modules/campaigns/repositories/campaigns-repository";
import { ContactListsRepository } from "@/modules/contacts/repositories/contact-lists-repository";
import { ContactsRepository } from "@/modules/contacts/repositories/contacts-repository";
import { TagsRepository } from "@/modules/contacts/repositories/tags-repository";
import { DomainsRepository } from "@/modules/domains/repositories/domains-repository";
import { SendersRepository } from "@/modules/senders/repositories/senders-repository";
import { SearchResultItem } from "../dtos/search-result-dto";

const RESULTS_PER_TYPE = 5;
const MIN_QUERY_LENGTH = 2;

interface GlobalSearchUseCaseRequest {
  query: string;
  userId: string;
}

interface GlobalSearchUseCaseResponse {
  results: SearchResultItem[];
}

export class GlobalSearchUseCase {
  constructor(
    private contactsRepository: ContactsRepository,
    private campaignsRepository: CampaignsRepository,
    private contactListsRepository: ContactListsRepository,
    private tagsRepository: TagsRepository,
    private domainsRepository: DomainsRepository,
    private sendersRepository: SendersRepository
  ) {}

  async execute({ query, userId }: GlobalSearchUseCaseRequest): Promise<GlobalSearchUseCaseResponse> {
    const trimmedQuery = query.trim();

    if (trimmedQuery.length < MIN_QUERY_LENGTH) {
      return { results: [] };
    }

    const [contacts, campaigns, contactLists, tags, domains, senders] = await Promise.all([
      this.contactsRepository.findPaginated({ skip: 0, take: RESULTS_PER_TYPE, search: trimmedQuery }),
      this.campaignsRepository.searchByUserId(userId, trimmedQuery, RESULTS_PER_TYPE),
      this.contactListsRepository.findAllPaginatedByUserId({
        userId,
        page: 1,
        pageSize: RESULTS_PER_TYPE,
        search: trimmedQuery,
      }),
      this.tagsRepository.findManyPaginated({ userId, page: 1, pageSize: RESULTS_PER_TYPE, search: trimmedQuery }),
      this.domainsRepository.searchByUserId(userId, trimmedQuery, RESULTS_PER_TYPE),
      this.sendersRepository.searchByUserId(userId, trimmedQuery, RESULTS_PER_TYPE),
    ]);

    const results: SearchResultItem[] = [
      ...contacts.map((contact) => ({
        type: "contact" as const,
        id: contact.id,
        title: contact.name || contact.email,
        subtitle: contact.name ? contact.email : undefined,
        href: `/contacts/${contact.id}`,
      })),
      ...campaigns.map((campaign) => ({
        type: "campaign" as const,
        id: campaign.id,
        title: campaign.title,
        subtitle: campaign.subject,
        href: `/campaigns/${campaign.id}`,
      })),
      ...contactLists.items.map((list) => ({
        type: "contact-list" as const,
        id: list.id,
        title: list.name,
        subtitle: list.description ?? undefined,
        href: "/contacts/lists",
      })),
      ...tags.items.map((tag) => ({
        type: "tag" as const,
        id: tag.id,
        title: tag.name,
        subtitle: tag.description ?? undefined,
        href: "/contacts/tags",
      })),
      ...domains.map((domain) => ({
        type: "domain" as const,
        id: domain.id,
        title: domain.domain,
        href: "/settings/domains",
      })),
      ...senders.map((sender) => ({
        type: "sender" as const,
        id: sender.id,
        title: sender.name,
        subtitle: sender.fromEmail,
        href: "/settings/domains",
      })),
    ];

    return { results };
  }
}
