import { CampaignEmailStatus, CampaignStatus, EmailMethod, Prisma } from '@prisma/client';
import { prisma } from '../../../config/database';
import { AppError } from '../../../middleware/error-handler';
import { emailQueueService } from '../../../services/email-queue.service';
import { recordCampaignEmail } from '../../../utils/metrics';
import { recordCrmActivity } from '../../../utils/crm-activity';
import { groupService } from '../../social/group.service';
import { achievementsService } from '../../social/achievements.service';
import type { SendCampaignEmailInput, TrackMailtoInput, ListCampaignEmailsInput } from './campaign-emails.schemas';

export const campaignEmailsService = {
  async sendEmail(slug: string, data: SendCampaignEmailInput, senderIp?: string) {
    const campaign = await prisma.campaign.findUnique({
      where: { slug },
      select: {
        id: true,
        slug: true,
        title: true,
        status: true,
        emailSubject: true,
        emailBody: true,
        allowSmtpEmail: true,
        allowMailtoLink: true,
        allowEmailEditing: true,
      },
    });

    if (!campaign) {
      throw new AppError(404, 'Campaign not found', 'CAMPAIGN_NOT_FOUND');
    }

    if (campaign.status !== CampaignStatus.ACTIVE) {
      throw new AppError(400, 'Campaign is not active', 'CAMPAIGN_NOT_ACTIVE');
    }

    if (data.emailMethod === EmailMethod.SMTP && !campaign.allowSmtpEmail) {
      throw new AppError(400, 'SMTP email is not enabled for this campaign', 'SMTP_NOT_ALLOWED');
    }

    if (data.emailMethod === EmailMethod.MAILTO && !campaign.allowMailtoLink) {
      throw new AppError(400, 'Mailto link is not enabled for this campaign', 'MAILTO_NOT_ALLOWED');
    }

    // Determine subject and body (custom only if campaign allows editing)
    const subject = (campaign.allowEmailEditing && data.customEmailSubject)
      ? data.customEmailSubject
      : campaign.emailSubject;

    const message = (campaign.allowEmailEditing && data.customEmailBody)
      ? data.customEmailBody
      : campaign.emailBody;

    const status = data.emailMethod === EmailMethod.SMTP
      ? CampaignEmailStatus.QUEUED
      : CampaignEmailStatus.CLICKED;

    const campaignEmail = await prisma.campaignEmail.create({
      data: {
        campaignId: campaign.id,
        campaignSlug: campaign.slug,
        userEmail: data.userEmail,
        userName: data.userName,
        userPostalCode: data.postalCode,
        recipientEmail: data.recipientEmail,
        recipientName: data.recipientName,
        recipientTitle: data.recipientTitle,
        recipientLevel: data.recipientLevel,
        emailMethod: data.emailMethod,
        subject,
        message,
        status,
        senderIp,
      },
    });

    if (data.emailMethod === EmailMethod.SMTP) {
      await emailQueueService.addCampaignEmail({
        campaignEmailId: campaignEmail.id,
        recipientEmail: data.recipientEmail,
        recipientName: data.recipientName,
        recipientLevel: data.recipientLevel,
        userEmail: data.userEmail,
        userName: data.userName,
        postalCode: data.postalCode,
        subject,
        message,
        campaignTitle: campaign.title,
      });
    }

    recordCampaignEmail(campaign.id);

    // CRM activity (fire-and-forget)
    recordCrmActivity({
      email: data.userEmail,
      activityType: 'EMAIL_SENT',
      title: `Sent campaign email: ${campaign.title}`,
      metadata: { campaignId: campaign.id, campaignSlug: campaign.slug, recipientEmail: data.recipientEmail, emailMethod: data.emailMethod },
    }).catch(() => {});

    // Social group sync (fire-and-forget)
    groupService.syncCampaignTeam(campaign.id).catch(() => {});

    // Achievement check for registered users (fire-and-forget)
    prisma.user.findUnique({ where: { email: data.userEmail }, select: { id: true } })
      .then((user) => {
        if (user) achievementsService.checkAndUnlock(user.id, ['campaigns']).catch(() => {});
      })
      .catch(() => {});

    // Fire-and-forget: check campaign milestones
    import('../../social/impact-stories.service').then(({ impactStoriesService }) => {
      impactStoriesService.checkMilestones(campaign.id).catch(() => {});
    }).catch(() => {});

    return {
      id: campaignEmail.id,
      status: campaignEmail.status,
      emailMethod: campaignEmail.emailMethod,
    };
  },

  async trackMailto(slug: string, data: TrackMailtoInput, senderIp?: string) {
    const campaign = await prisma.campaign.findUnique({
      where: { slug },
      select: {
        id: true,
        slug: true,
        title: true,
        status: true,
        emailSubject: true,
        emailBody: true,
        allowMailtoLink: true,
      },
    });

    if (!campaign) {
      throw new AppError(404, 'Campaign not found', 'CAMPAIGN_NOT_FOUND');
    }

    if (campaign.status !== CampaignStatus.ACTIVE) {
      throw new AppError(400, 'Campaign is not active', 'CAMPAIGN_NOT_ACTIVE');
    }

    const campaignEmail = await prisma.campaignEmail.create({
      data: {
        campaignId: campaign.id,
        campaignSlug: campaign.slug,
        userEmail: data.userEmail,
        userName: data.userName,
        userPostalCode: data.postalCode,
        recipientEmail: data.recipientEmail,
        recipientName: data.recipientName,
        recipientTitle: data.recipientTitle,
        recipientLevel: data.recipientLevel,
        emailMethod: EmailMethod.MAILTO,
        subject: campaign.emailSubject,
        message: campaign.emailBody,
        status: CampaignEmailStatus.CLICKED,
        senderIp,
      },
    });

    // Social group sync (fire-and-forget)
    groupService.syncCampaignTeam(campaign.id).catch(() => {});

    // Fire-and-forget: check campaign milestones
    import('../../social/impact-stories.service').then(({ impactStoriesService }) => {
      impactStoriesService.checkMilestones(campaign.id).catch(() => {});
    }).catch(() => {});

    return {
      id: campaignEmail.id,
      status: campaignEmail.status,
      emailMethod: campaignEmail.emailMethod,
    };
  },

  async listByCampaign(campaignId: string, filters: ListCampaignEmailsInput) {
    const { page, limit, status, emailMethod } = filters;
    const skip = (page - 1) * limit;

    const where: Prisma.CampaignEmailWhereInput = { campaignId };
    if (status) where.status = status;
    if (emailMethod) where.emailMethod = emailMethod;

    const [emails, total] = await Promise.all([
      prisma.campaignEmail.findMany({
        where,
        skip,
        take: limit,
        orderBy: { sentAt: 'desc' },
        select: {
          id: true,
          userEmail: true,
          userName: true,
          userPostalCode: true,
          recipientEmail: true,
          recipientName: true,
          recipientLevel: true,
          emailMethod: true,
          subject: true,
          status: true,
          sentAt: true,
        },
      }),
      prisma.campaignEmail.count({ where }),
    ]);

    return {
      emails,
      pagination: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    };
  },

  async getStats(campaignId: string) {
    const [totals, byMethod] = await Promise.all([
      prisma.campaignEmail.groupBy({
        by: ['status'],
        where: { campaignId },
        _count: true,
      }),
      prisma.campaignEmail.groupBy({
        by: ['emailMethod'],
        where: { campaignId },
        _count: true,
      }),
    ]);

    const stats: Record<string, number> = {
      total: 0,
      queued: 0,
      sent: 0,
      failed: 0,
      clicked: 0,
      smtpCount: 0,
      mailtoCount: 0,
    };

    for (const row of totals) {
      stats.total += row._count;
      const key = row.status.toLowerCase();
      if (key in stats) stats[key] = row._count;
    }

    for (const row of byMethod) {
      if (row.emailMethod === EmailMethod.SMTP) stats.smtpCount = row._count;
      if (row.emailMethod === EmailMethod.MAILTO) stats.mailtoCount = row._count;
    }

    return stats;
  },
};
