import { Types } from 'mongoose';
import { Campaign } from './campaign.model';
import {
  NewCreatedCampaign,
  PopulatedCampaign,
  UpdateCampaignBody,
} from './campaign.interface';
import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { safeDeleteById } from '@/shared/utils/guard/ref-guard';
import { TemplateName } from '@/shared/constants';
import config from '@/shared/config/config';
import { sendEmailWithActiveTemplate } from '../communication/email/email.helper';
import { sendBatchWhatsAppMessages } from './campaign.helper';
import dayjs from 'dayjs';
import isBetween from 'dayjs/plugin/isBetween';
dayjs.extend(isBetween);

const { CampaignResponseCodes } = responseCodes;

export const createCampaign = async (data: NewCreatedCampaign) => {
  try {
    const campaign = await Campaign.create(data);

    const campaignData = await Campaign.findById(campaign._id)

      .populate([
        {
          path: 'createdBy',
          select: 'email',
        },
        {
          path: 'company',
          select: 'name',
        },
      ])
      .lean<PopulatedCampaign>();

    await sendEmailWithActiveTemplate({
      to: campaignData.createdBy.email,
      companyId: campaign.company as Types.ObjectId,
      scenario: TemplateName.CampaignStatus,
      templateParams: {
        fullName: `${campaignData.createdBy.firstName} ${campaignData.createdBy.lastName}`,
        companyName: campaignData.company.name,
        campaignName: campaignData.name,
        duration: campaignData.spreadDuration,
        status: campaignData.status,
        campaignUrl: `${config.clientUrl}/campaigns/analytics/${campaignData._id}`,
      },
    });

    return campaign;
  } catch (error) {
    console.error('🚀 ~ createCampaign ~ error:', error);
    throw new ApiError(
      defaultStatus.OK,
      'Failed to create campaign',
      true,
      '',
      CampaignResponseCodes.CAMPAIGN_ERROR,
    );
  }
};

export const updateCampaign = async (
  id: string,
  updateData: UpdateCampaignBody,
) => {
  const campaign = await Campaign.findByIdAndUpdate(id, updateData, {
    new: true,
  });

  if (!campaign)
    throw new ApiError(
      defaultStatus.OK,
      'Campaign not found',
      true,
      '',
      CampaignResponseCodes.CAMPAIGN_NOT_FOUND,
    );

  await sendBatchWhatsAppMessages(campaign, updateData);

  return campaign;
};

export const deleteCampaign = async (id: string) => {
  await safeDeleteById(Campaign, id, CampaignResponseCodes.CAMPAIGN_IN_USE);

  return true;
};

export const getCampaignById = async (id: string) => {
  const campaign = await Campaign.findById(id)
    .populate('company')
    .populate('category')
    .populate('subCategories')
    .populate('targetedCity')
    .populate('targetedAreas');

  if (!campaign)
    throw new ApiError(
      defaultStatus.OK,
      'Campaign not found',
      true,
      '',
      CampaignResponseCodes.CAMPAIGN_NOT_FOUND,
    );

  return campaign;
};

/**
 * Calculate campaign statistics using Day.js
 */
export const getCampaignStats = async (filter) => {
  try {
    const now = dayjs();

    const currentMonthStart = now.startOf('month').toDate();
    const currentMonthEnd = now.endOf('month').toDate();

    const prevMonthStart = now.subtract(1, 'month').startOf('month').toDate();
    const prevMonthEnd = now.subtract(1, 'month').endOf('month').toDate();

    // Total campaigns count
    const totalCount = await Campaign.countDocuments(filter);

    const currentMonthCount = await Campaign.countDocuments({
      ...filter,
      createdAt: { $gte: currentMonthStart, $lte: currentMonthEnd },
    });

    const prevMonthCount = await Campaign.countDocuments({
      ...filter,
      createdAt: { $gte: prevMonthStart, $lte: prevMonthEnd },
    });

    let trend: 'up' | 'down' | 'neutral' = 'neutral';
    if (currentMonthCount > prevMonthCount) trend = 'up';
    else if (currentMonthCount < prevMonthCount) trend = 'down';

    // Running campaigns
    const runningCount = await Campaign.countDocuments({ status: 'running', ...filter });

    const currentMonthRunning = await Campaign.countDocuments({
      ...filter,
      status: 'running',
      createdAt: { $gte: currentMonthStart, $lte: currentMonthEnd },
    });

    const prevMonthRunning = await Campaign.countDocuments({
      ...filter,
      status: 'running',
      createdAt: { $gte: prevMonthStart, $lte: prevMonthEnd },
    });

    let runningTrend: 'up' | 'down' | 'neutral' = 'neutral';
    if (currentMonthRunning > prevMonthRunning) runningTrend = 'up';
    else if (currentMonthRunning < prevMonthRunning) runningTrend = 'down';

    return {
      totalCampaigns: {
        count: totalCount,
        trend,
        change: currentMonthCount - prevMonthCount,
      },
      runningCampaigns: {
        count: runningCount,
        trend: runningTrend,
        change: currentMonthRunning - prevMonthRunning,
      },
    };
  } catch (error) {
    console.error('🚀 ~ getCampaignStats ~ error:', error);
    throw new ApiError(
      defaultStatus.INTERNAL_SERVER_ERROR,
      'Failed to calculate campaign stats',
      true,
      '',
      CampaignResponseCodes.CAMPAIGN_ERROR,
    );
  }
};

export const queryCampaigns = async (filter = {}, options = {}) => {
  try {
    const result = await Campaign.paginate(filter, options);

    const stats = await getCampaignStats(filter);

    return {
      ...result,
      stats,
    };
  } catch (error) {
    console.error('🚀 ~ queryCampaigns ~ error:', error);
    throw new ApiError(
      defaultStatus.INTERNAL_SERVER_ERROR,
      'Failed to query campaigns',
      true,
      '',
      CampaignResponseCodes.CAMPAIGN_ERROR,
    );
  }
};
