import { prisma } from '../../../config/database';
import { smsQueueService } from '../../../services/sms-queue.service';
import type { CreateSmsCampaignInput, UpdateSmsCampaignInput } from './sms-campaigns.schemas';

export const smsCampaignsService = {
  /**
   * Create a campaign and copy contact list entries into recipients.
   */
  async create(data: CreateSmsCampaignInput, userId?: string) {
    // Verify contact list exists
    const list = await prisma.smsContactList.findUnique({
      where: { id: data.contactListId },
      include: { entries: { select: { phone: true, name: true } } },
    });
    if (!list) throw new Error('Contact list not found');

    const campaign = await prisma.smsCampaign.create({
      data: {
        name: data.name,
        messageTemplate: data.messageTemplate,
        contactListId: data.contactListId,
        advocacyCampaignId: data.advocacyCampaignId || undefined,
        delayBetweenMs: data.delayBetweenMs,
        totalRecipients: list.entries.length,
        createdByUserId: userId,
      },
    });

    // Copy contact list entries into campaign recipients
    if (list.entries.length > 0) {
      await prisma.smsCampaignRecipient.createMany({
        data: list.entries.map((entry) => ({
          campaignId: campaign.id,
          phone: entry.phone,
          name: entry.name,
        })),
      });
    }

    return campaign;
  },

  async findAll(page = 1, limit = 50) {
    const skip = (page - 1) * limit;
    const [items, total] = await Promise.all([
      prisma.smsCampaign.findMany({
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
        include: {
          contactList: { select: { id: true, name: true } },
          advocacyCampaign: { select: { id: true, title: true, slug: true } },
          createdByUser: { select: { id: true, name: true, email: true } },
        },
      }),
      prisma.smsCampaign.count(),
    ]);
    return { items, total, page, limit };
  },

  async findById(id: string) {
    return prisma.smsCampaign.findUnique({
      where: { id },
      include: {
        contactList: { select: { id: true, name: true, totalContacts: true } },
        advocacyCampaign: { select: { id: true, title: true, slug: true } },
        createdByUser: { select: { id: true, name: true, email: true } },
        _count: { select: { recipients: true, messages: true, conversations: true } },
      },
    });
  },

  async update(id: string, data: UpdateSmsCampaignInput) {
    const campaign = await prisma.smsCampaign.findUnique({ where: { id }, select: { status: true } });
    if (!campaign) throw new Error('Campaign not found');
    if (campaign.status !== 'DRAFT') throw new Error('Can only edit campaigns in DRAFT status');

    return prisma.smsCampaign.update({ where: { id }, data });
  },

  async delete(id: string) {
    const campaign = await prisma.smsCampaign.findUnique({ where: { id }, select: { status: true } });
    if (!campaign) throw new Error('Campaign not found');
    if (campaign.status !== 'DRAFT') throw new Error('Can only delete campaigns in DRAFT status');

    await prisma.smsCampaign.delete({ where: { id } });
  },

  /**
   * Start campaign: set RUNNING, enqueue all pending recipients.
   */
  async start(id: string) {
    const campaign = await prisma.smsCampaign.findUnique({ where: { id } });
    if (!campaign) throw new Error('Campaign not found');
    if (campaign.status !== 'DRAFT' && campaign.status !== 'PAUSED') {
      throw new Error('Can only start campaigns in DRAFT or PAUSED status');
    }

    await prisma.smsCampaign.update({
      where: { id },
      data: {
        status: 'RUNNING',
        startedAt: campaign.startedAt || new Date(),
      },
    });

    const enqueued = await smsQueueService.enqueueCampaignRecipients(id, campaign.delayBetweenMs);
    return { enqueued };
  },

  /**
   * Pause campaign: set PAUSED. Worker checks status before each message.
   */
  async pause(id: string) {
    const campaign = await prisma.smsCampaign.findUnique({ where: { id }, select: { status: true } });
    if (!campaign) throw new Error('Campaign not found');
    if (campaign.status !== 'RUNNING') throw new Error('Can only pause running campaigns');

    await prisma.smsCampaign.update({ where: { id }, data: { status: 'PAUSED' } });
  },

  /**
   * Resume campaign: set RUNNING, re-enqueue remaining PENDING recipients.
   */
  async resume(id: string) {
    const campaign = await prisma.smsCampaign.findUnique({ where: { id } });
    if (!campaign) throw new Error('Campaign not found');
    if (campaign.status !== 'PAUSED') throw new Error('Can only resume paused campaigns');

    await prisma.smsCampaign.update({ where: { id }, data: { status: 'RUNNING' } });
    const enqueued = await smsQueueService.enqueueCampaignRecipients(id, campaign.delayBetweenMs);
    return { enqueued };
  },

  /**
   * Get live status of a campaign: sent/failed/pending/total counts.
   */
  async getStatus(id: string) {
    const campaign = await prisma.smsCampaign.findUnique({
      where: { id },
      select: { status: true, totalRecipients: true, totalSent: true, totalFailed: true, totalResponded: true, startedAt: true, completedAt: true },
    });
    if (!campaign) throw new Error('Campaign not found');

    const pending = await prisma.smsCampaignRecipient.count({ where: { campaignId: id, status: 'PENDING' } });

    return {
      ...campaign,
      pending,
    };
  },

  /**
   * Get recipients for a campaign (paginated)
   */
  async getRecipients(campaignId: string, page = 1, limit = 100, statusFilter?: string) {
    const skip = (page - 1) * limit;
    const where: Record<string, unknown> = { campaignId };
    if (statusFilter) where.status = statusFilter;

    const [items, total] = await Promise.all([
      prisma.smsCampaignRecipient.findMany({
        where,
        orderBy: { createdAt: 'asc' },
        skip,
        take: limit,
      }),
      prisma.smsCampaignRecipient.count({ where }),
    ]);
    return { items, total, page, limit };
  },
};
