import { ApiError } from '@/shared/utils/errors';
import { defaultStatus } from '@/shared/utils/responseCode/httpStatusAlias';
import responseCodes from '@/shared/utils/responseCode/responseCode';
import { Types } from 'mongoose';
import {
  buildActivityCountPipeline,
  buildLeadInterestTypeCountPipeline,
  buildLeadStageCountPipeline,
  buildPropertyCategoryCountPipeline,
  calculateBuilderMetrics,
  calculateLeadStats,
  calculatePaymentStats,
  calculateProjectStats,
  calculateUnitStats,
  countLeadsWithoutActivity,
  getActiveLeadsSummary,
  getActivityStats,
  getBrokerStats,
  getLeadSourceStats,
  getPersonalTargetPipeline,
  getSalesPerformanceMetrics,
  getTeamActivitySummary,
  getTeamActivitySummaryReport as getTeamActivitySummaryReportPipeline,
} from './dashboard.pipeline';
import { LeadStage } from '../master/leadStage/leadStage.model';
import { individualProperties } from '../individualProperties';
import { Lead } from '../lead/lead.model';
import { Targets } from '../targets/targets.model';
import { Tasks } from '../tasks/tasks.model';
import {
  getCompanyStatsAggregation,
  getConversionRatios,
  getExpiringSubscriptions,
  getFinancialSummary,
  getLeadSources,
  getLowEngagementList,
  getMonthlyDataPerformanceAllCompanies,
  getRevenueMetrics,
  getTopActiveClients,
  getUsageOverview,
  getUserStatsAggregation,
} from './superAdminDashboard.pipeline';
import * as rulesService from '@/modules/rules/rules.service';
import { getObjectId } from '@/shared/utils/commonHelper';
import { getDateString } from '@/shared/utils/date';
import { TaskStatus } from '../tasks/tasks.constant';
import { getOrphanLeadsCount } from '../lead/lead.service';

const { DashboardResponseCodes } = responseCodes;

export const getBrokerDashboard = async (
  brokerId: Types.ObjectId,
  userType: string,
  companyId: Types.ObjectId,
  filters?: { projectId?: Types.ObjectId; startDate?: Date; endDate?: Date },
) => {
  if (!brokerId && userType !== 'admin')
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'Broker ID is required',
      true,
      '',
      DashboardResponseCodes.BROKER_ID_REQUIRED,
    );

  const todayDate = getDateString(new Date(), 'YYYY-MM-DD');

  const taskFilter =
    userType === 'admin'
      ? { companyId: getObjectId(companyId) }
      : {
          companyId: getObjectId(companyId),
          assignedTo: getObjectId(brokerId),
        };

  const pipeline = buildActivityCountPipeline(taskFilter, todayDate);

  const activityCounts = await Tasks.aggregate(pipeline);

  const rules = await rulesService.getRules(
    companyId,
    'see_all_leads',
    'see_all_contacts',
    'see_all_customers',
  );

  const leadStageCountPipeline = buildLeadStageCountPipeline(
    getObjectId(companyId),
    userType,
    getObjectId(brokerId),
    rules,
  );

  const leadStageCount = await LeadStage.aggregate(leadStageCountPipeline);

  const propertyPipeline = buildPropertyCategoryCountPipeline(
    companyId,
    userType,
    brokerId,
  );
  const propertyCategoryCounts =
    await individualProperties.aggregate(propertyPipeline);

  const leadPipeline = buildLeadInterestTypeCountPipeline(
    companyId,
    userType,
    brokerId,
  );
  const leadInterestCounts = await Lead.aggregate(leadPipeline);

  const salesData = await getSalesPerformanceMetrics(
    companyId,
    userType,
    brokerId,
    rules,
  );

  const personalTargetsAggregation = await Targets.aggregate(
    getPersonalTargetPipeline({
      companyId,
      memberId: brokerId,
    }),
  );

  const targetData = personalTargetsAggregation.length
    ? personalTargetsAggregation[0]
    : {
        salesAmount: { target: 0, achieved: 0 },
        unitsSold: { target: 0, achieved: 0 },
        meetings: { target: 0, achieved: 0 },
        siteVisits: { target: 0, achieved: 0 },
        calls: { target: 0, achieved: 0 },
      };

  const stats = await getBrokerStats(userType, companyId, brokerId);

  const teamSummary = await getTeamActivitySummary(
    brokerId,
    companyId,
    userType,
  );

  const leadSourceStats = await getLeadSourceStats(
    userType,
    companyId,
    brokerId,
  );

  const leadsWithoutActivity = await countLeadsWithoutActivity(brokerId);

  const taskStatsPipeline = [
    {
      $match: {
        ...taskFilter,
      },
    },
    {
      $group: {
        _id: null,
        total_overdue_tasks: { 
          $sum: {
            $cond: [
              {
                $eq: ['$status', TaskStatus.OVERDUE],
              },
              1,
              0,
            ],
          },
        },
      },
    },
  ];

  const taskStatsResult = await Tasks.aggregate(taskStatsPipeline);

  const taskStats = taskStatsResult[0] || { total_overdue_tasks: 0 };

  const orphan_leads = await getOrphanLeadsCount({
    company: companyId,
    assignedTo: userType !== 'admin' ? brokerId : undefined,
  });

  const activityStats = await getActivityStats(userType, companyId, brokerId);

  return {
    activityCounts,
    leadStageCount,
    propertyCategoryCounts,
    leadInterestCounts,
    salesData,
    targetData,
    stats,
    teamSummary,
    leadSourceStats,
    activityStats,
    // eslint-disable-next-line camelcase
    lead_count_without_activity: leadsWithoutActivity || 0,
    total_overdue_tasks: taskStats.total_overdue_tasks || 0,
    orphan_leads: orphan_leads || 0,
  };
};

export const getTeamActivitySummaryReport = async (
  adminId: Types.ObjectId,
  userType: string,
  companyId: Types.ObjectId,
  filters?: {
    startDate?: Date;
    endDate?: Date;
    source?: string;
    projectId?: string;
  },
) => {
  let source: Types.ObjectId | { $in: Types.ObjectId[] } | undefined;

  if (filters.source) {
    if (filters.source.includes(',')) {
      source = {
        $in: filters.source.split(',').map((id) => getObjectId(id.trim())),
      };
    } else {
      source = getObjectId(filters.source);
    }
  }

  const parsedFilters = {
    ...filters,
    source,
  };

  return getTeamActivitySummaryReportPipeline(
    adminId,
    companyId,
    userType,
    parsedFilters,
  );
};

export const getSuperAdminDashboard = async (
  adminId: Types.ObjectId,
  // userType: string,
  companyId: Types.ObjectId,
  filter?: { startDate?: string; endDate?: string },
) => {
  const activeCompanies = await getCompanyStatsAggregation(companyId, filter);

  const activeUsers = await getUserStatsAggregation(adminId, filter);

  const financialSummary = await getFinancialSummary(filter);

  const revenueMetrics = await getRevenueMetrics(adminId, companyId, filter);

  const dataPerformance = await getMonthlyDataPerformanceAllCompanies(filter);

  const conversionRatios = await getConversionRatios(filter);

  const leadSources = await getLeadSources(filter);

  const featureUsageOverview = await getUsageOverview(filter);

  const expiringSubscriptions = await getExpiringSubscriptions(filter);

  const lowEngagementWatchlist = await getLowEngagementList(filter);

  const topActiveClients = await getTopActiveClients(filter);

  return {
    activeCompanies,
    activeUsers,
    financialSummary,
    revenueMetrics,
    dataPerformance,
    conversionRatios,
    leadSources,
    featureUsageOverview,
    expiringSubscriptions,
    lowEngagementWatchlist,
    topActiveClients,
  };
};

export const getBuilderDashboard = async (
  builderId: Types.ObjectId,
  userType: string,
  companyId: Types.ObjectId,
) => {
  if (!builderId && userType !== 'admin')
    throw new ApiError(
      defaultStatus.BAD_REQUEST,
      'Builder ID is required',
      true,
      '',
      DashboardResponseCodes.BROKER_ID_REQUIRED,
    );

  const metrics = await calculateBuilderMetrics(companyId);

  const personalTargetsAggregation = await Targets.aggregate(
    getPersonalTargetPipeline({
      companyId,
      memberId: builderId,
    }),
  );

  const targetData = personalTargetsAggregation.length
    ? personalTargetsAggregation[0]
    : {
        salesAmount: { target: 0, achieved: 0 },
        unitsSold: { target: 0, achieved: 0 },
        meetings: { target: 0, achieved: 0 },
        siteVisits: { target: 0, achieved: 0 },
        calls: { target: 0, achieved: 0 },
      };

  const [
    projectStats,
    financialSummary,
    unitsSummary,
    leadStats,
    activeLeadsSummary,
    leadsWithoutActivity,
  ] = await Promise.all([
    calculateProjectStats(companyId),
    calculatePaymentStats(companyId),
    calculateUnitStats(companyId),
    calculateLeadStats(companyId),
    getActiveLeadsSummary(companyId),
    countLeadsWithoutActivity(builderId),
  ]);

  const stats = {
    projectStats,
    financialSummary,
    unitsSummary,
    leadStats,
    activeLeadsSummary,
  };

  const now = new Date();

  const taskStatsPipeline = [
    {
      $match: {
        companyId: getObjectId(companyId),
        isDeleted: { $ne: true },
      },
    },
    {
      $group: {
        _id: null,
        total_overdue_tasks: {
          $sum: {
            $cond: [
              {
                $or: [
                  { $eq: ['$status', TaskStatus.OVERDUE] },
                  {
                    $and: [
                      { $lt: ['$activityDate', now] },
                      { $ne: ['$status', TaskStatus.COMPLETED] },
                      { $ne: ['$status', TaskStatus.CANCELLED] },
                    ],
                  },
                ],
              },
              1,
              0,
            ],
          },
        },
      },
    },
  ];

  const taskStatsResult = await Tasks.aggregate(taskStatsPipeline);

  const taskStats = taskStatsResult[0] || { total_overdue_tasks: 0 };

  const orphan_leads = await getOrphanLeadsCount({
    company: companyId,
    assignedTo: userType !== 'admin' ? builderId : undefined,
  });

  const activityStats = await getActivityStats(userType, companyId, builderId);

  return {
    metrics,
    targetData,
    stats,
    taskStats,
    activityStats,
    lead_count_without_activity: leadsWithoutActivity || 0,
    total_overdue_tasks: taskStats.total_overdue_tasks || 0,
    orphan_leads: orphan_leads || 0,
  };
};
