const db = require('../db/models');
const ActivitiesDBApi = require('../db/api/activities');

const ACTIVITY_TYPES = new Set(['call', 'email', 'meeting', 'task', 'demo', 'note']);

function httpError(message, code = 400) {
  const error = new Error(message);
  error.code = code;
  return error;
}

function cleanText(value) {
  return typeof value === 'string' ? value.trim() : '';
}

function parseRequiredDate(value, fieldName) {
  const date = new Date(value);

  if (!value || Number.isNaN(date.getTime())) {
    throw httpError(`${fieldName} must be a valid date and time.`);
  }

  return date;
}

module.exports = class SalesWorkflowService {
  static async scheduleFollowUp(data, currentUser) {
    if (!currentUser || !currentUser.id) {
      throw httpError('You must be signed in to schedule a follow-up.', 403);
    }

    const dealId = cleanText(data?.dealId || data?.deal);
    const activityType = cleanText(data?.activity_type) || 'task';
    const subject = cleanText(data?.subject);
    const details = cleanText(data?.details);
    const dueAt = parseRequiredDate(data?.due_at, 'Follow-up time');
    const reminderAt = data?.reminder_at
      ? parseRequiredDate(data.reminder_at, 'Reminder time')
      : new Date(dueAt.getTime() - 30 * 60 * 1000);

    if (!dealId) {
      throw httpError('A deal is required before scheduling a follow-up.');
    }

    if (!ACTIVITY_TYPES.has(activityType)) {
      throw httpError('Activity type must be call, email, meeting, task, demo, or note.');
    }

    if (!subject) {
      throw httpError('Subject is required before scheduling a follow-up.');
    }

    const transaction = await db.sequelize.transaction();

    try {
      const deal = await db.deals.findByPk(dealId, { transaction });

      if (!deal) {
        throw httpError('Deal not found.', 404);
      }

      const activityPayload = {
        activity_type: activityType,
        subject,
        details,
        scheduled_at: dueAt,
        due_at: dueAt,
        status: 'planned',
        is_reminder_enabled: data?.is_reminder_enabled !== false,
        reminder_at: reminderAt,
        assigned_to: currentUser.id,
        deal: deal.id,
        lead: deal.leadId || null,
        contact: deal.primary_contactId || null,
      };

      const activity = await ActivitiesDBApi.create(
        activityPayload,
        {
          currentUser,
          transaction,
        },
      );

      await deal.update(
        {
          next_follow_up_at: dueAt,
          updatedById: currentUser.id,
        },
        { transaction },
      );

      await transaction.commit();

      return {
        activity: {
          id: activity.id,
          activity_type: activity.activity_type,
          subject: activity.subject,
          due_at: activity.due_at,
          status: activity.status,
        },
        deal: {
          id: deal.id,
          name: deal.name,
          next_follow_up_at: deal.next_follow_up_at,
        },
      };
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }
};
