import mongoose from 'mongoose';
import moment from 'moment';

import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import { Support } from '@/modules/support/support.model';
import {
  ISupportFilter,
  ISupportPopulated,
  NewCreatedSupport,
  UpdateSupportBody,
} from '@/modules/support/support.interface';
import responseCodes from '@/shared/utils/responseCode/responseCode';

import { PaginateOptions } from '@/shared/utils/plugins/paginate/paginate';
import User from '../user/user.model';
import { TemplateName } from '@/shared/constants';
import config from '@/shared/config/config';
import { sendEmailWithActiveTemplate } from '../communication/email/email.helper';

const { SupportResponseCodes } = responseCodes;

export const createSupport = async (
  data: NewCreatedSupport,
): Promise<boolean> => {
  try {
    const support = await Support.create(data);

    const userData = await User.findById(data.userId);

    if (!userData)
      throw new ApiError(
        defaultStatus.OK,
        'Failed to create support',
        true,
        '',
        SupportResponseCodes.SUPPORT_ERROR,
      );

    if (!support)
      throw new ApiError(
        defaultStatus.OK,
        'Failed to create support',
        true,
        '',
        SupportResponseCodes.SUPPORT_ERROR,
      );

    await sendEmailWithActiveTemplate({
      to: userData.email,
      companyId: support.companyId,
      scenario: TemplateName.SupportRequest,
      templateParams: {
        fullName: `${userData.firstName} ${userData.lastName}`,
        requestId: `${support._id.toString().slice(0, 4)}`,
        date: moment(support.createdAt).format('dddd DD MMM YYYY, hh:mm A'),
        message: support.query,
        supportUrl: `${config.clientUrl}/support`,
      },
    });

    return true;
  } catch (_error) {
    throw new ApiError(
      defaultStatus.OK,
      'Failed to create support',
      true,
      '',
      SupportResponseCodes.SUPPORT_ERROR,
    );
  }
};

export const getSupportById = async (id: string) => {
  const support = await Support.findById(id);
  if (!support)
    throw new ApiError(
      defaultStatus.OK,
      'Support not found',
      true,
      '',
      SupportResponseCodes.COMPANY_NOT_FOUND,
    );

  return support;
};

export const updateSupport = async (
  id: string,
  updateData: UpdateSupportBody,
): Promise<boolean | null> => {
  try {
    const support = (await Support.findByIdAndUpdate(id, updateData, {
      new: true,
    })
      .populate({
        path: 'userId',
        select: 'firstName lastName email userType',
      })
      .populate({
        path: 'companyId',
        select: 'name',
      })) as unknown as ISupportPopulated;

    if (!support)
      throw new ApiError(
        defaultStatus.OK,
        'Support not found',
        true,
        '',
        SupportResponseCodes.COMPANY_NOT_FOUND,
      );

    await sendEmailWithActiveTemplate({
      to: support.userId.email,
      companyId: support.companyId,
      scenario: TemplateName.SupportResponse,
      templateParams: {
        fullName: `${support.userId.firstName} ${support.userId.lastName}`,
        requestId: `${id.toString().slice(0, 4)}`,
        date: support.createdAt.toISOString().split('T')[0],
        response: support.reply,
        supportUrl: `${config.clientUrl}/support`,
      },
    });

    // await sendTransactionalEmail({
    //   to: support.userId.email,
    //   subject: `🛠 Support Response from ${support.companyId.name}`,
    //   htmlContent: emailContent,
    // }).catch((err) => {
    //   console.error('Background sendEmail failed:', err);
    //   // can manage queue here
    // });

    return true;
  } catch (_error) {
    throw new ApiError(
      defaultStatus.OK,
      'Failed to update support',
      true,
      '',
      SupportResponseCodes.COMPANY_ERROR,
    );
  }
};

export const querySupport = async (
  filter: ISupportFilter = {},
  options: PaginateOptions = {},
) => {
  const searchTerm = (filter.search || '').trim();

  let queryFilter: { [key: string]: unknown } = {};

  if (filter.status) queryFilter.status = filter.status;

  if (filter.companyId && mongoose.Types.ObjectId.isValid(filter.companyId))
    queryFilter.companyId = new mongoose.Types.ObjectId(filter.companyId);

  if (filter.userId && mongoose.Types.ObjectId.isValid(filter.userId))
    queryFilter.userId = new mongoose.Types.ObjectId(filter.userId);

  const pipeline: unknown[] = [
    { $match: queryFilter },

    {
      $lookup: {
        from: 'users',
        localField: 'userId',
        foreignField: '_id',
        as: 'user',
      },
    },
    { $unwind: '$user' },

    {
      $lookup: {
        from: 'companies',
        localField: 'companyId',
        foreignField: '_id',
        as: 'company',
      },
    },
    { $unwind: '$company' },
    {
      $project: {
        id: '$_id',
        status: 1,
        query: 1,
        reply: 1,
        repliedAt: 1,
        createdAt: 1,
        createdBy: 1,
        'user.phone': {
          $concat: [
            '+',
            { $toString: '$user.phone.dialCode' },
            ' ',
            { $toString: '$user.phone.number' },
          ],
        },
        'user.firstName': 1,
        'user.lastName': 1,
        'user.email': 1,
        'user.userType': 1,
        'company.name': 1,
      },
    },
  ];

  if (searchTerm)
    pipeline.push({
      $match: {
        $or: [
          { 'user.firstName': { $regex: searchTerm, $options: 'i' } },
          { 'user.lastName': { $regex: searchTerm, $options: 'i' } },
          { 'company.name': { $regex: searchTerm, $options: 'i' } },
        ],
      },
    });

  const result = await Support.paginate(
    {},
    { ...options, aggregation: pipeline },
  );

  return result;
};
