import { ContactList, MarketingChannel, Prisma } from "@prisma/client";
import { prisma } from "@/shared/infra/prisma/prisma-client";
import {
  ContactListsRepository,
  ContactListWithCount,
  FindAllPaginatedByUserIdParams,
  FindAllPaginatedByUserIdResult,
} from "./contact-lists-repository";

export class PrismaContactListsRepository implements ContactListsRepository {
  async findAllByUserId(userId: string): Promise<ContactListWithCount[]> {
    return prisma.contactList.findMany({
      where: { userId },
      include: { _count: { select: { memberships: true } } },
      orderBy: { createdAt: "desc" },
    });
  }

  async findAllPaginatedByUserId({
    userId,
    page,
    pageSize,
    search,
    marketingChannel,
    createdFrom,
    createdTo,
  }: FindAllPaginatedByUserIdParams): Promise<FindAllPaginatedByUserIdResult> {
    const where: Prisma.ContactListWhereInput = {
      userId,
      ...(search && { name: { contains: search, mode: "insensitive" } }),
      ...(marketingChannel && { marketingChannel }),
      ...((createdFrom || createdTo) && {
        createdAt: {
          ...(createdFrom && { gte: createdFrom }),
          ...(createdTo && { lte: createdTo }),
        },
      }),
    };

    const [items, total] = await Promise.all([
      prisma.contactList.findMany({
        where,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { createdAt: "desc" },
      }),
      prisma.contactList.count({ where }),
    ]);

    const activeCounts = await prisma.contactListMembership.groupBy({
      by: ["listId"],
      where: { listId: { in: items.map((item) => item.id) }, contact: { status: "ACTIVE" } },
      _count: { _all: true },
    });

    const activeCountByListId = new Map(activeCounts.map((c) => [c.listId, c._count._all]));

    return {
      items: items.map((item) => ({ ...item, activeContactsCount: activeCountByListId.get(item.id) ?? 0 })),
      total,
    };
  }

  async findById(id: string): Promise<ContactList | null> {
    return prisma.contactList.findUnique({ where: { id } });
  }

  async findByUserIdAndName(userId: string, name: string): Promise<ContactList | null> {
    return prisma.contactList.findUnique({ where: { userId_name: { userId, name } } });
  }

  async create(data: {
    name: string;
    description?: string;
    userId: string;
    marketingChannel?: MarketingChannel;
  }): Promise<ContactList> {
    return prisma.contactList.create({ data });
  }

  async delete(id: string): Promise<void> {
    await prisma.contactList.delete({ where: { id } });
  }

  async addContactsToLists(contactIds: string[], listIds: string[]): Promise<void> {
    const pairs = contactIds.flatMap((contactId) =>
      listIds.map((listId) => ({ contactId, listId }))
    );

    await prisma.contactListMembership.createMany({
      data: pairs,
      skipDuplicates: true,
    });
  }

  async removeContactFromList(contactId: string, listId: string): Promise<void> {
    await prisma.contactListMembership.delete({
      where: { contactId_listId: { contactId, listId } },
    });
  }
}
