import { Request, Response } from 'express';
import { catchAsync, pick, sanitizeLeadRow } from '@/shared/utils';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import * as leadService from '@/modules/lead/lead.service';
import {
  bulkLeadRowSchema,
  partitionDuplicatePhones,
} from '@/modules/lead/lead.validation';
import { getObjectId } from '@/shared/utils/commonHelper';
import { updateLeadScoreFromActivity } from '../leadScore/leadScore.service';
import { ILeadDoc, NewCreatedLead } from './lead.interface';
import { IContactDoc } from '../contacts/contacts.interface';
import { Lead } from './lead.model';
import { Contact } from '../contacts/contacts.model';
import * as contactService from '@/modules/contacts/contacts.service';
import { LeadStage } from '../master/leadStage/leadStage.model';
import * as activityService from '@/modules/activity/activity.service';
import { Types } from 'mongoose';
import { TaskActivityType } from '../tasks/tasks.constant';
import * as tasksService from '@/modules/tasks/tasks.service';
import ExcelJS from 'exceljs';
import * as rulesService from '@/modules/rules/rules.service';
import * as teamsService from '@/modules/teams/teams.service';
import { LeadPriority, UserType } from '@/shared/constants/enum.constant';
import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import IndividualProperties from '@/modules/individualProperties/individualProperties.model';
import Project from '@/modules/project/project.model';

const { LeadResponseCodes } = responseCodes;

export const getLeadActivityCounts = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = req.params;
    const counts = await leadService.getLeadActivityCounts(id as string);
    res.success(
      counts,
      LeadResponseCodes.SUCCESS,
      'Lead Activity Counts Fetched',
    );
  },
);

export const recalculateLeadActivityCounts = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = req.params;
    const counts = await leadService.recalculateLeadActivityCounts(id as string);
    res.success(
      counts,
      LeadResponseCodes.SUCCESS,
      'Lead Activity Counts Recalculated',
    );
  },
);

export const createLead = catchAsync(async (req: Request, res: Response) => {
  const { company } = req.user;
  const companyId = company?.id;
  const lead = await leadService.createLead({
    ...req.body,
    company: companyId,
  });

  const rules = (await rulesService.getRules(
    companyId,
    'auto_create_call_task',
  )) as { auto_create_call_task?: boolean | null };
  const autoCreateCallTask = rules.auto_create_call_task !== false;

  let task: Awaited<ReturnType<typeof tasksService.createTasks>> | undefined;
  if (autoCreateCallTask) {
    const taskPayload = {
      assignedTo: lead.assignedTo,
      notes: 'New Lead Added',
      activityType: TaskActivityType.CALL,
      activityDate: new Date(),
      callStatus: 'scheduled' as const,
      companyId,
      leadId: getObjectId(lead._id.toString()),
      createdBy: lead.createdBy,
      source: lead?.source,
    };

    task = await tasksService.createTasks(taskPayload);
  }

  await updateLeadScoreFromActivity('contact_added', lead?.id);

  await activityService.createActivity({
    title: 'Lead Created',
    comment: 'New lead created successfully.',
    type: 'schedule' as const,
    lead: lead?.id as Types.ObjectId,
    contact: lead?.contact,
    company: companyId,
    status: 'completed',
    assignedTo: lead?.assignedTo,
    createdBy: lead?.createdBy,
    createdAt: lead?.createdAt,
  });

  if (task) {
    await activityService.createActivity({
      title: 'Schedule - call',
      type: 'notes' as const,
      task: task.id as Types.ObjectId,
      lead: lead?.id as Types.ObjectId,
      company: companyId,
      status: 'pending',
      assignedTo: lead?.assignedTo,
      createdBy: lead?.createdBy,
      createdAt: task.createdAt,
      scheduleDateTime: lead?.createdAt,
    });
  }

  res.success(lead, LeadResponseCodes.SUCCESS, 'Lead Created Successfully');
});

export const createBulkLead = catchAsync(
  async (req: Request, res: Response) => {
    const { company } = req.user;
    const companyId = company?.id;
    const leadsPayload = req.body as any[];
    const bulkCreatedBy = (req as { body?: { createdBy?: Types.ObjectId } }).body
      ?.createdBy;

    const totalRequested = Array.isArray(leadsPayload) ? leadsPayload.length : 0;

    // Validate each row individually with Joi, collect errors, skip invalid rows
    const rowErrors: string[] = [];
    const joiValidRows: { row: any; originalRowIndex: number }[] = [];

    if (!Array.isArray(leadsPayload)) {
      return res.success(
        {
          created: 0,
          skipped: 0,
          totalRequested: 0,
          errors: ['Request body must be an array of lead rows.'],
        },
        LeadResponseCodes.SUCCESS,
        'No leads imported: invalid request body.',
      );
    }

    leadsPayload.forEach((row: any, i: number) => {
      const { error } = bulkLeadRowSchema.validate(row, { abortEarly: false });
      if (error) {
        const messages = error.details.map((d) => d.message).join('; ');
        rowErrors.push(`Row ${i + 1}: ${messages}`);
      } else {
        joiValidRows.push({ row, originalRowIndex: i });
      }
    });

    const { uniqueRows, duplicateErrors } = partitionDuplicatePhones(
      joiValidRows.map(({ row, originalRowIndex }) => ({
        row,
        originalRowIndex,
      })),
    );
    rowErrors.push(...duplicateErrors);

    const defaultStage = await LeadStage.findOne({
      company: companyId,
      position: 1,
      isActive: true,
    });

    const bulkRules = (await rulesService.getRules(
      companyId,
      'auto_create_call_task',
    )) as { auto_create_call_task?: boolean | null };
    const autoCreateCallTask = bulkRules.auto_create_call_task !== false;

    let created = 0;
    const creationErrors: string[] = [];

    for (const { row: rawRow, originalRowIndex } of uniqueRows) {
      const rowLabel = `Row ${originalRowIndex + 1}`;
      const displayHint = `${rawRow.firstName || 'Lead'} / ${rawRow.phone || 'no phone'}`;

      if (!defaultStage) {
        creationErrors.push(
          `${rowLabel} (${displayHint}): No default lead stage is configured for your company. Ask an administrator to set an active stage at position 1.`,
        );
        continue;
      }

      const row = sanitizeLeadRow(rawRow) as Record<string, any>;

      try {
        const contact = await contactService.findOrCreateByPhone({
          firstName: row.firstName,
          lastName: row.lastName,
          phone: row.phone,
          secondaryPhone: row.secondaryPhone,
          email: row.email,
          secondaryEmail: row.secondaryEmail,
          company: companyId,
          createdBy: bulkCreatedBy,
          source: row.source,
        });

        const lead = await leadService.createLead({
          ...row,
          company: companyId,
          contact: contact._id,
          createdBy: bulkCreatedBy,
          priority: LeadPriority.MEDIUM,
          leadStage: defaultStage._id,
        } as NewCreatedLead);

        await activityService.createActivity({
          title: 'Lead Created',
          comment: 'New lead created successfully.',
          type: 'notes' as const,
          lead: lead?.id as Types.ObjectId,
          contact: lead?.contact,
          company: companyId,
          status: 'completed',
          assignedTo: lead?.assignedTo,
          createdBy: lead?.createdBy,
          createdAt: lead?.createdAt,
        });

        if (row.notes && row.notes.trim())
          await activityService.createActivity({
            title: 'Notes Added',
            comment: row.notes,
            type: 'notes' as const,
            lead: lead?.id as Types.ObjectId,
            contact: lead?.contact,
            company: companyId,
            status: 'completed',
            assignedTo: lead?.assignedTo,
            createdBy: lead?.createdBy,
            createdAt: new Date(lead?.createdAt.getTime() + 1),
          });

        const contactActivityPayload = {
          title: 'Contact Created',
          comment: 'New contact created successfully.',
          type: 'notes' as const,
          contact: lead?.contact,
          company: companyId,
          status: 'completed' as const,
          assignedTo: lead?.assignedTo,
          createdBy: lead?.createdBy,
          createdAt: lead?.createdAt,
        };

        await activityService.createActivity(contactActivityPayload);

        if (autoCreateCallTask) {
          const taskPayload = {
            assignedTo: lead.assignedTo,
            notes: 'New Lead Added',
            activityType: TaskActivityType.CALL,
            activityDate: new Date(),
            callStatus: 'scheduled' as const,
            companyId,
            leadId: getObjectId(lead._id.toString()),
            createdBy: lead.createdBy,
            source: lead?.source,
          };

          await tasksService.createTasks(taskPayload);
        }

        await updateLeadScoreFromActivity('contact_added', lead?.id);
        created += 1;
      } catch (err: unknown) {
        const msg =
          err instanceof ApiError
            ? err.message
            : err instanceof Error
              ? err.message
              : 'Failed to create lead';
        creationErrors.push(`${rowLabel} (${displayHint}): ${msg}`);
      }
    }

    const allErrors = [...rowErrors, ...creationErrors];
    const skipped = totalRequested - created;

    res.success(
      {
        created,
        skipped,
        totalRequested,
        errors: allErrors,
      },
      LeadResponseCodes.SUCCESS,
      `Bulk import finished: ${created} created, ${skipped} skipped.`,
    );
  },
);

export const getLeadById = catchAsync(async (req: Request, res: Response) => {
  const { id } = pick(req.params, ['id']);
  const lead = await leadService.getLeadById(id);

  const contactId =
    lead.contact instanceof Types.ObjectId
      ? lead.contact.toString()
      : (lead.contact as unknown as { _id: Types.ObjectId })._id.toString();

  const leadsWithSameContact =
    await leadService.countLeadsByContactId(contactId);

  (lead as any)._doc.contactCount = leadsWithSameContact;

  res.success(lead, LeadResponseCodes.SUCCESS, 'Lead Retrieved Successfully');
});

export const exportLeads = catchAsync(async (req: Request, res: Response) => {
  const filter = pick(req.query, [
    'leadStage',
    'companyName',
    'search',
    'createdBy',
    'interestType',
    'source',
    'assignedTo',
    'preferredCity',
    'preferredLocalities',
    'budget',
    'category',
    'subcategory',
    'project',
    'propertyType',
    'configuration',
    'orphanLeads',
    'ids',
  ]);
  filter.company = req.user.company.id;
  const companyId = req.user.company.id;
  // Check export permission
  const rules = (await rulesService.getRules(
    companyId,
    'export_data',
  )) as Record<string, boolean>;
  const canExport = rules.export_data || req.user.userType === UserType.ADMIN;
  if (!canExport)
    return res.status(403).json({
      message: 'Export not allowed',
      code: LeadResponseCodes.LEAD_ERROR,
    });

  // Query leads without pagination
  const options = {
    limit: 10000, // High limit for export
    populate:
      'contact:firstName,lastName,email,phone;source:name;leadStage:stageName;assignedTo:firstName,lastName;createdBy:firstName,lastName;configuration:name',
  };
  const leads = await leadService.queryLeads(filter, options);
  // Create Excel
  const workbook = new ExcelJS.Workbook();
  const worksheet = workbook.addWorksheet('Leads');
  // Headers
  worksheet.columns = [
    { header: 'Lead Score', key: 'leadScore', width: 10 },
    { header: 'Priority', key: 'priority', width: 10 },
    { header: 'First Name', key: 'firstName', width: 20 },
    { header: 'Last Name', key: 'lastName', width: 20 },
    { header: 'Email', key: 'email', width: 25 },
    { header: 'Phone Number', key: 'phoneNumber', width: 15 },
    { header: 'Interest', key: 'interest', width: 15 },
    { header: 'Configuration', key: 'configuration', width: 20 },
    { header: 'Lead Stage', key: 'leadStage', width: 15 },
    { header: 'Lead Source', key: 'leadSource', width: 15 },
    { header: 'Last Contacted', key: 'lastContacted', width: 20 },
    { header: 'Assigned To', key: 'assignedTo', width: 20 },
  ];
  // Add rows
  leads.results.forEach((lead: any) => {
    const nameParts = lead.contactDetails?.name?.split(' ') || [];
    worksheet.addRow({
      leadScore: lead.leadScore || 0,
      priority: lead.priority,
      firstName: nameParts[0] || '',
      lastName: nameParts.slice(1).join(' ') || '',
      email: lead.contactDetails?.email || '',
      phoneNumber:
        lead.contact?.phone?.find((p) => p.isPrimary)?.number ||
        lead.contact?.phone?.[0]?.number ||
        '',
      interest: lead.interestType,
      configuration: lead.configuration
        ? lead.configuration.map((c: any) => c.name).join(', ')
        : '',
      leadStage: lead.leadStage?.stageName || '',
      leadSource: lead.source?.name || '',
      lastContacted: lead.updatedAt
        ? new Date(lead.updatedAt).toLocaleDateString()
        : '',
      assignedTo: lead.assignedTo
        ? `${lead.assignedTo.firstName} ${lead.assignedTo.lastName}`
        : '',
    });
  });
  res.setHeader(
    'Content-Type',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  );
  res.setHeader('Content-Disposition', 'attachment; filename=leads.xlsx');
  const buffer = await workbook.xlsx.writeBuffer();
  res.send(buffer);
});

export const updateShortList = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = req.params;
    const { company } = req.user;
    const { type, propertyId, model, projectId } = req.query;

    // 🔹 Validate: at least one of propertyId or projectId must be provided
    if ((!propertyId && !projectId) || (propertyId && projectId))
      return res.status(400).json({
        message: 'Provide either propertyId or projectId (but not both).',
        code: LeadResponseCodes.LEAD_ERROR,
      });

    // 🔹 Validate type
    if (!['add', 'remove', 'delete'].includes(type as string))
      return res.status(400).json({
        message: "Invalid type. Use 'add', 'remove' or 'delete'.",
        code: LeadResponseCodes.LEAD_ERROR,
      });

    let updatedEntity: ILeadDoc | IContactDoc;
    let activityLeadId: Types.ObjectId | undefined;
    let activityContactId: Types.ObjectId | undefined;
    let activityAssignedTo: Types.ObjectId;

    const userObjectId = getObjectId(req.user.id);

    if (model === 'lead') {
      const lead = await Lead.findOne<ILeadDoc>({
        _id: id,
        company: company?.id,
      });
      if (!lead)
        return res.status(404).json({
          message: 'Lead not found',
          code: LeadResponseCodes.LEAD_NOT_FOUND,
        });

      updatedEntity = await leadService.handleShortlistUpdate(lead, {
        propertyId: propertyId as string | undefined,
        projectId: projectId as string | undefined,
        type: type as 'add' | 'remove' | 'delete',
      });
      activityLeadId = getObjectId(id as string);
      activityContactId = lead.contact;
      activityAssignedTo = lead.assignedTo ?? userObjectId;
    } else if (model === 'contact') {
      const contact = await Contact.findOne<IContactDoc>({
        _id: id,
        company: company?.id,
      });
      if (!contact)
        return res.status(404).json({
          message: 'Contact not found',
          code: LeadResponseCodes.LEAD_NOT_FOUND,
        });

      updatedEntity = await leadService.handleShortlistUpdate(contact, {
        propertyId: propertyId as string | undefined,
        projectId: projectId as string | undefined,
        type: type as 'add' | 'remove' | 'delete',
      });
      activityContactId = getObjectId(id as string);
      activityAssignedTo = userObjectId;
    } else {
      return res.status(400).json({
        message: "Invalid model. Use 'lead' or 'contact'.",
        code: LeadResponseCodes.LEAD_ERROR,
      });
    }

    const shortlistType = type as 'add' | 'remove' | 'delete';
    const companyId = company?.id;

    if (companyId) {
      let entityName = '';
      if (propertyId) {
        const prop = await IndividualProperties.findById(propertyId)
          .select('title')
          .lean<{ title?: string }>();
        entityName = prop?.title?.trim() || 'Unknown property';
      } else if (projectId) {
        const proj = await Project.findById(projectId)
          .select('projectName')
          .lean<{ projectName?: string }>();
        entityName = proj?.projectName?.trim() || 'Unknown project';
      }

      const kind = projectId ? 'Project' : 'Property';
      let title: string;
      let comment: string;
      if (shortlistType === 'add') {
        title = `${kind} shortlisted`;
        comment = `${entityName} was added to shortlisted.`;
      } else if (shortlistType === 'remove') {
        title = `${kind} rejected`;
        comment = `${entityName} was marked as rejected (removed from shortlisted).`;
      } else {
        title = `${kind} restored from rejected`;
        comment = `${entityName} was removed from the rejected list.`;
      }

      const activityPayload: Parameters<typeof activityService.createActivity>[0] =
      {
        title,
        comment,
        type: 'notes',
        status: 'completed',
        company: companyId,
        createdBy: userObjectId,
        assignedTo: activityAssignedTo,
        ...(propertyId
          ? { property: getObjectId(propertyId as string) }
          : {}),
        ...(projectId ? { project: getObjectId(projectId as string) } : {}),
        ...(activityLeadId ? { lead: activityLeadId } : {}),
        ...(activityContactId ? { contact: activityContactId } : {}),
      };

      try {
        await activityService.createActivity(activityPayload);
      } catch (err) {
        console.error('Failed to create shortlist activity timeline entry', err);
      }
    }

    return res.success(
      updatedEntity,
      LeadResponseCodes.SUCCESS,
      `${model} shortlist updated successfully`,
    );
  },
);

export const getSuggestedProperties = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = pick(req.params, ['id']);
    const { model } = pick(req.query, ['model']);

    // Extract filter parameters
    const filters = pick(req.query, [
      'subcategory',
      'propertyType',
      'budgetMin',
      'budgetMax',
      'furnishingType',
    ]);

    const lead = await leadService.getSuggestedPropertiesByLeadOrContact(
      id,
      model,
      filters,
    );
    res.success(
      lead,
      LeadResponseCodes.SUCCESS,
      'Suggested Properties Successfully',
    );
  },
);

export const addSuggestedProperties = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = pick(req.params, ['id']);
    const { propertyIds } = pick(req.body, ['propertyIds']);
    const { company } = req.user;
    let companyId: string = undefined;
    if (company?.id) {
      if (typeof company?.id === 'string') {
        companyId = company?.id;
      } else {
        companyId = company?.id.toString();
      }
    }

    const result = await leadService.addPropertiesToSuggested(
      id,
      propertyIds,
      companyId,
    );

    res.success(
      result,
      LeadResponseCodes.SUCCESS,
      'Properties added to suggested list successfully',
    );
  },
);

export const getSuggestedProjects = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = pick(req.params, ['id']);
    const { model } = pick(req.query, ['model']);
    const { team } = req.user;
    const lead = await leadService.getSuggestedProjectsByLeadOrContact(
      id,
      model,
      team,
    );
    res.success(
      lead,
      LeadResponseCodes.SUCCESS,
      'Suggested Projects Successfully',
    );
  },
);

// export const updateLead = catchAsync(async (req: Request, res: Response) => {
//   const updated = await leadService.updateLead(req.params.leadId, req.body);
//   res.success(updated, LeadResponseCodes.SUCCESS, 'Lead Updated Successfully');
// });

export const checkIfRefLead = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = pick(req.params, ['id']);
    await leadService.checkIfRefLead(id);
    res.success(null, LeadResponseCodes.SUCCESS, 'Lead Deleted Successfully');
  },
);

export const deleteLeadById = catchAsync(
  async (req: Request, res: Response) => {
    const { id } = pick(req.params, ['id']);
    await leadService.deleteLeadById(id);
    res.success(null, LeadResponseCodes.SUCCESS, 'Lead Deleted Successfully');
  },
);

export const queryLeads = catchAsync(async (req: Request, res: Response) => {
  const usertype: UserType = req?.user?.userType;
  const filter = pick(req.query, [
    'company',
    'leadStage',
    'companyName',
    'search',
    'createdBy',
    'interestType',
    'source',
    'assignedTo',
    'preferredCity',
    'preferredLocalities',
    'budget',
    'category',
    'subcategory',
    'project',
    'propertyType',
    'configuration',
    'orphanLeads',
    'view',
    'stage',
    'minActivity',
    'maxActivity',
  ]);
  const options = pick(req.query, [
    'sortBy',
    'limit',
    'page',
    'fields',
    'populate',
    'includeTimeStamps',
    'alias',
  ]);

  if (usertype !== UserType.SUPERADMIN) {
    filter.company = req.user.company.id;
  }


  if (usertype !== UserType.SUPERADMIN) {
    const companyId = req.user.company?.id;
    const rules = (await rulesService.getRules(companyId, 'see_all_leads')) as {
      see_all_leads?: boolean;
    };
    if (usertype !== UserType.ADMIN && !rules?.see_all_leads) {
      const teamIds = (req.user.team || []).map((id: Types.ObjectId | string) =>
        getObjectId(id),
      );
      const assigneeIds = await teamsService.getVisibleAssigneeIdsForUser(
        getObjectId(req.user._id),
        teamIds,
      );
      if (filter.assignedTo) {
        // Handle comma-separated IDs from the filter
        const requestedIds = typeof filter.assignedTo === 'string'
          ? filter.assignedTo
            .split(',')
            .map((id) => id.trim())
            .filter((id) => Types.ObjectId.isValid(id))
            .map((id) => getObjectId(id))
          : [getObjectId(filter.assignedTo)];

        // Filter to only include assignees that the user can see
        const allowedIds = requestedIds.filter((requestedId) =>
          assigneeIds.some((id) => id.equals(requestedId))
        );

        // Set the filter based on how many allowed IDs we have
        if (allowedIds.length === 0) {
          filter.assignedTo = { $in: [] }; // No matches, return empty results
        } else if (allowedIds.length === 1) {
          filter.assignedTo = allowedIds[0]; // Single ID
        } else {
          filter.assignedTo = { $in: allowedIds }; // Multiple IDs
        }
      } else {
        filter.assignedTo =
          assigneeIds.length === 1 ? assigneeIds[0] : { $in: assigneeIds };
      }
    }
  }

  const orphanLeadsCount = await leadService.getOrphanLeadsCount(filter);

  if (filter.view === 'kanban') {
    if (filter.stage) {
      const kanbanData = await leadService.queryLeadsKanban(filter, options);
      return res.success(
        kanbanData,
        LeadResponseCodes.SUCCESS,
        'Kanban Column Fetched Successfully',
      );
    } else {
      const kanbanData = await leadService.queryLeadsKanbanGrouped(
        filter,
        options,
      );
      (kanbanData as any).orphanLeadsCount = orphanLeadsCount;
      return res.success(
        kanbanData,
        LeadResponseCodes.SUCCESS,
        'Kanban View Fetched Successfully',
      );
    }
  }

  if (filter.leadStage === 'all') {
    delete filter.leadStage;
  }

  const leads = await leadService.queryLeads(filter, options);
  (leads as any).orphanLeadsCount = orphanLeadsCount;

  res.success(leads, LeadResponseCodes.SUCCESS, 'Leads Fetched Successfully');
});

export const updateLead = catchAsync(async (req: Request, res: Response) => {
  const { id } = req.params;
  const { checkCustomFieldValidation } = pick(req.query, [
    'checkCustomFieldValidation',
  ]);
  const { company, firstName, lastName } = req.user;

  const updateData = req.body;
  updateData.company = company?.id;

  const updatedLead = await leadService.updateLead(
    id as string,
    updateData,
    {
      firstName,
      lastName,
    },
    checkCustomFieldValidation ?? true,
    req.user.userType,
  );

  res.success(
    updatedLead,
    LeadResponseCodes.SUCCESS,
    'Lead Updated Successfully',
  );
});

export const bulkDeleteLeads = catchAsync(
  async (req: Request, res: Response) => {
    const { ids } = req.body;
    const result = await leadService.bulkDeleteLeads(ids);
    res.success(
      result,
      LeadResponseCodes.SUCCESS,
      `Successfully deleted ${result.deletedCount} leads`,
    );
  },
);

export const bulkUpdateLeads = catchAsync(
  async (req: Request, res: Response) => {
    const { ids, updateData } = req.body;
    const { company, firstName, lastName } = req.user;

    const updateDataWithCompany = {
      ...updateData,
      company: company?.id,
    };

    const updatedLeads = await leadService.bulkUpdateLeads(
      ids,
      updateDataWithCompany,
      {
        firstName,
        lastName,
      },
      req.user.userType,
    );

    res.success(
      updatedLeads,
      LeadResponseCodes.SUCCESS,
      `${updatedLeads.length} Lead(s) Updated Successfully`,
    );
  },
);

export const getLeadAnalytics = catchAsync(
  async (req: Request, res: Response) => {
    const userId = req.user?.id;
    const companyId = req.user?.company?.id;
    const userType = req.user?.userType;

    const analytics = await leadService.getLeadAnalytics(
      companyId,
      userType === 'admin' ? undefined : userId,
    );

    res.success(
      analytics,
      LeadResponseCodes.SUCCESS,
      'Lead Analytics Fetched Successfully',
    );
  },
);

export const transferLead = catchAsync(async (req: Request, res: Response) => {
  const { company, userType } = req.user;
  const companyId = company?.id;

  if (userType !== UserType.ADMIN && userType !== UserType.SUPERADMIN) {
    const rules = (await rulesService.getRules(
      companyId,
      'transfer_leads',
    )) as Record<string, boolean>;

    if (!rules.transfer_leads)
      throw new ApiError(
        defaultStatus.FORBIDDEN,
        'Transferring leads between teams is disabled by company rules',
        true,
        '',
        LeadResponseCodes.LEAD_ERROR,
      );
  }

  const leadTransfer = await leadService.transferLead({
    ...req.body,
    company: companyId,
  });

  res.success(
    leadTransfer,
    LeadResponseCodes.SUCCESS,
    'Lead(s) transferred successfully',
  );
});

/**
 * Get MyOperator status for a lead
 * GET /api/v1/lead/:leadId/myoperator-status
 */
export const getLeadMyOperatorStatus = catchAsync(
  async (req: Request, res: Response) => {
    const { leadId } = req.params;
    const userId = req.user._id;
    const companyId = req.user.company.id;

    const status = await leadService.getLeadMyOperatorStatus(
      leadId as string,
      userId,
      companyId,
    );

    res.success(
      status,
      LeadResponseCodes.SUCCESS,
      'MyOperator status retrieved successfully',
    );
  },
);

/**
 * Get call history for a lead
 * GET /api/v1/lead/:leadId/call-history
 */
export const getLeadCallHistory = catchAsync(
  async (req: Request, res: Response) => {
    const { leadId } = req.params;
    const companyId = req.user.company.id;
    const page = req.query.page ? parseInt(req.query.page as string) : 1;
    const pageSize = req.query.pageSize
      ? parseInt(req.query.pageSize as string)
      : 20;

    const history = await leadService.getLeadCallHistory(
      leadId as string,
      companyId,
      page,
      pageSize,
    );

    res.success(
      history,
      LeadResponseCodes.SUCCESS,
      'Call history retrieved successfully',
    );
  },
);

export const moveLead = catchAsync(async (req: Request, res: Response) => {
  const { id } = req.params;
  const { stage, beforeId, afterId } = req.body;

  const updatedLead = await leadService.moveLead(
    id as string,
    stage as string,
    beforeId as string | undefined,
    afterId as string | undefined,
  );

  res.success(
    updatedLead,
    LeadResponseCodes.SUCCESS,
    'Lead moved successfully',
  );
});
