import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from '@/store/store';
import type { CrmStats, LeadSource, DealStage, TaskStatus } from '../types/CrmTypes';

// Base selectors
export const selectCrmState = (state: RootState) => state.crm;

export const selectLeads = (state: RootState) => state.crm.leads;
export const selectTasks = (state: RootState) => state.crm.tasks;
export const selectContacts = (state: RootState) => state.crm.contacts;
export const selectDeals = (state: RootState) => state.crm.deals;
export const selectSalesOrders = (state: RootState) => state.crm.salesOrders;
export const selectPurchaseOrders = (state: RootState) => state.crm.purchaseOrders;
export const selectInvoices = (state: RootState) => state.crm.invoices;

export const selectCrmLoading = (state: RootState) => state.crm.loading;
export const selectCrmErrors = (state: RootState) => state.crm.errors;
export const selectCrmPagination = (state: RootState) => state.crm.pagination;

// Pagination selectors for infinite scrolling
export const selectLeadsPagination = (state: RootState) => state.crm.pagination.leads;
export const selectTasksPagination = (state: RootState) => state.crm.pagination.tasks;
export const selectContactsPagination = (state: RootState) => state.crm.pagination.contacts;
export const selectDealsPagination = (state: RootState) => state.crm.pagination.deals;
export const selectSalesOrdersPagination = (state: RootState) => state.crm.pagination.salesOrders;
export const selectPurchaseOrdersPagination = (state: RootState) => state.crm.pagination.purchaseOrders;
export const selectInvoicesPagination = (state: RootState) => state.crm.pagination.invoices;

// Loading selectors
export const selectLeadsLoading = (state: RootState) => state.crm.loading.leads;
export const selectTasksLoading = (state: RootState) => state.crm.loading.tasks;
export const selectContactsLoading = (state: RootState) => state.crm.loading.contacts;
export const selectDealsLoading = (state: RootState) => state.crm.loading.deals;
export const selectSalesOrdersLoading = (state: RootState) => state.crm.loading.salesOrders;
export const selectPurchaseOrdersLoading = (state: RootState) => state.crm.loading.purchaseOrders;
export const selectInvoicesLoading = (state: RootState) => state.crm.loading.invoices;

// Error selectors
export const selectLeadsError = (state: RootState) => state.crm.errors.leads;
export const selectTasksError = (state: RootState) => state.crm.errors.tasks;
export const selectContactsError = (state: RootState) => state.crm.errors.contacts;
export const selectDealsError = (state: RootState) => state.crm.errors.deals;
export const selectSalesOrdersError = (state: RootState) => state.crm.errors.salesOrders;
export const selectPurchaseOrdersError = (state: RootState) => state.crm.errors.purchaseOrders;
export const selectInvoicesError = (state: RootState) => state.crm.errors.invoices;

// Computed selectors for dashboard
// Counts selector
export const selectCrmCounts = (state: RootState) => state.crm.counts;

// KPIs selector
export const selectCrmKPIs = (state: RootState) => state.crm.kpis;

export const selectCrmStats = createSelector(
  [selectLeads, selectTasks, selectContacts, selectDeals, selectSalesOrders, selectPurchaseOrders, selectInvoices],
  (leads, tasks, contacts, deals, salesOrders, purchaseOrders, invoices): CrmStats => {
    // Ensure arrays are defined and are actually arrays, fallback to empty arrays
    const safeLeads = Array.isArray(leads) ? leads : [];
    const safeTasks = Array.isArray(tasks) ? tasks : [];
    const safeContacts = Array.isArray(contacts) ? contacts : [];
    const safeDeals = Array.isArray(deals) ? deals : [];
    const safeSalesOrders = Array.isArray(salesOrders) ? salesOrders : [];
    const safePurchaseOrders = Array.isArray(purchaseOrders) ? purchaseOrders : [];
    const safeInvoices = Array.isArray(invoices) ? invoices : [];

    // Calculate leads stats with safe property access and better fallbacks
    const leadsByStatus = safeLeads.reduce((acc, lead) => {
      const status = lead?.Lead_Status && lead.Lead_Status.trim() !== '' ? lead.Lead_Status : 'Not Set';
      acc[status] = (acc[status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const leadsBySource = safeLeads.reduce((acc, lead) => {
      const source = lead?.Lead_Source && lead.Lead_Source.trim() !== '' ? lead.Lead_Source : 'Not Set';
      acc[source] = (acc[source] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // Calculate tasks stats with safe property access and better fallbacks
    const tasksByStatus = safeTasks.reduce((acc, task) => {
      const status = task?.Status && task.Status.trim() !== '' ? task.Status : 'Not Set';
      acc[status] = (acc[status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const tasksByPriority = safeTasks.reduce((acc, task) => {
      const priority = task?.Priority && task.Priority.trim() !== '' ? task.Priority : 'Not Set';
      acc[priority] = (acc[priority] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // Calculate contacts stats with safe property access
    const contactsByCompany = safeContacts.reduce((acc, contact) => {
      const company = contact?.Account_Name?.name || 'Unknown';
      acc[company] = (acc[company] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    // Calculate deals stats with safe property access and better fallbacks
    const dealsByStage = safeDeals.reduce((acc, deal) => {
      const stage = deal?.Stage && deal.Stage.trim() !== '' ? deal.Stage : 'Not Set';
      acc[stage] = (acc[stage] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const totalDealValue = safeDeals.reduce((sum, deal) => {
      const amount = deal?.Amount || 0;
      return sum + (typeof amount === 'number' && !isNaN(amount) ? amount : 0);
    }, 0);
    
    const wonDeals = safeDeals.filter(deal => deal?.Stage === 'Closed Won');
    const lostDeals = safeDeals.filter(deal => deal?.Stage === 'Closed Lost');

    // Calculate sales orders stats
    const salesOrdersByStatus = safeSalesOrders.reduce((acc, order) => {
      const status = order?.Status && order.Status.trim() !== '' ? order.Status : 'Not Set';
      acc[status] = (acc[status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const salesOrdersByCountry = safeSalesOrders.reduce((acc, order) => {
      const country = order?.Billing_Country && order.Billing_Country.trim() !== '' ? order.Billing_Country : 'Not Set';
      acc[country] = (acc[country] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const totalSalesOrderValue = safeSalesOrders.reduce((sum, order) => {
      const amount = order?.Grand_Total || 0;
      return sum + (typeof amount === 'number' && !isNaN(amount) ? amount : 0);
    }, 0);

    // Calculate purchase orders stats
    const purchaseOrdersByStatus = safePurchaseOrders.reduce((acc, order) => {
      const status = order?.Status && order.Status.trim() !== '' ? order.Status : 'Not Set';
      acc[status] = (acc[status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const purchaseOrdersByVendor = safePurchaseOrders.reduce((acc, order) => {
      const vendor = order?.Vendor_Name?.name || 'Unknown';
      acc[vendor] = (acc[vendor] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const totalPurchaseOrderValue = safePurchaseOrders.reduce((sum, order) => {
      const amount = order?.Grand_Total || 0;
      return sum + (typeof amount === 'number' && !isNaN(amount) ? amount : 0);
    }, 0);

    // Calculate invoices stats
    const invoicesByStatus = safeInvoices.reduce((acc, invoice) => {
      const status = invoice?.Status && invoice.Status.trim() !== '' ? invoice.Status : 'Not Set';
      acc[status] = (acc[status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const totalInvoiceValue = safeInvoices.reduce((sum, invoice) => {
      const amount = invoice?.Grand_Total || 0;
      return sum + (typeof amount === 'number' && !isNaN(amount) ? amount : 0);
    }, 0);

    const overdueInvoices = safeInvoices.filter(invoice => {
      if (!invoice?.Due_Date) return false;
      return new Date(invoice.Due_Date) < new Date() && invoice.Status !== 'Paid';
    });

    const paidInvoices = safeInvoices.filter(invoice => invoice?.Status === 'Paid');

    // Calculate Customer & Sales KPIs
    const calculateCustomerKPIs = () => {
      // 1. Sales Cycle Length - Average days from deal creation to close
      const closedDeals = safeDeals.filter(deal => 
        deal?.Stage === 'Closed Won' && deal?.Created_Time && deal?.Modified_Time
      );
      const salesCycleLength = closedDeals.length > 0 
        ? closedDeals.reduce((total, deal) => {
            const created = new Date(deal.Created_Time);
            const closed = new Date(deal.Modified_Time);
            const daysDiff = Math.ceil((closed.getTime() - created.getTime()) / (1000 * 60 * 60 * 24));
            return total + daysDiff;
          }, 0) / closedDeals.length
        : 0;

      // 2. Average Revenue Per Account - Total deal value / unique accounts
      const uniqueAccounts = new Set(
        safeDeals
          .filter(deal => deal?.Account_Name?.name)
          .map(deal => deal.Account_Name.name)
      );
      const totalDealValue = safeDeals.reduce((sum, deal) => sum + (deal?.Amount || 0), 0);
      const averageRevenuePerAccount = uniqueAccounts.size > 0 
        ? totalDealValue / uniqueAccounts.size 
        : 0;

      // 3. Churn Rate - Lost leads / total leads (using lead status)
      const lostLeads = safeLeads.filter(lead => 
        lead?.Lead_Status === 'Lost Lead' || lead?.Lead_Status === 'Unqualified'
      );
      const churnRate = safeLeads.length > 0 
        ? (lostLeads.length / safeLeads.length) * 100 
        : 0;

      // 4. Customer Lifetime Value - Average deal value per customer
      const wonDeals = safeDeals.filter(deal => deal?.Stage === 'Closed Won');
      const totalWonValue = wonDeals.reduce((sum, deal) => sum + (deal?.Amount || 0), 0);
      const customerLifetimeValue = uniqueAccounts.size > 0 
        ? totalWonValue / uniqueAccounts.size 
        : 0;

      // 5. LTV-to-CAC Ratio (estimated - using average deal value as proxy for LTV)
      // Assuming CAC is 20% of average deal value (this would need real marketing spend data)
      const estimatedCAC = customerLifetimeValue * 0.2;
      const ltvToCacRatio = estimatedCAC > 0 
        ? customerLifetimeValue / estimatedCAC 
        : 0;

      // 6. Customer Retention Rate
      const customerRetentionRate = 100 - churnRate;

      // 7. Average Deal Size
      const averageDealSize = safeDeals.length > 0 
        ? totalDealValue / safeDeals.length 
        : 0;

      // 8. Conversion Rate - Converted leads / total leads
      const convertedLeads = safeLeads.filter(lead => lead?.Lead_Status === 'Converted');
      const conversionRate = safeLeads.length > 0 
        ? (convertedLeads.length / safeLeads.length) * 100 
        : 0;

      // 9. Win Rate - Won deals / total deals
      const winRate = safeDeals.length > 0 
        ? (wonDeals.length / safeDeals.length) * 100 
        : 0;

      return {
        salesCycleLength: Math.round(salesCycleLength),
        averageRevenuePerAccount: Math.round(averageRevenuePerAccount),
        churnRate: Math.round(churnRate * 100) / 100,
        customerLifetimeValue: Math.round(customerLifetimeValue),
        ltvToCacRatio: Math.round(ltvToCacRatio * 100) / 100,
        customerRetentionRate: Math.round(customerRetentionRate * 100) / 100,
        averageDealSize: Math.round(averageDealSize),
        conversionRate: Math.round(conversionRate * 100) / 100,
        winRate: Math.round(winRate * 100) / 100,
      };
    };

    const customerKPIs = calculateCustomerKPIs();

    return {
      leads: {
        total: safeLeads.length,
        new: leadsByStatus['New'] || 0,
        qualified: leadsByStatus['Qualified'] || 0,
        converted: leadsByStatus['Converted'] || 0,
        bySource: leadsBySource as Record<LeadSource, number>,
        byStatus: leadsByStatus as Record<string, number>,
      },
      tasks: {
        total: safeTasks.length,
        completed: tasksByStatus['Completed'] || 0,
        overdue: safeTasks.filter(task => 
          new Date(task.Due_Date) < new Date() && task.Status !== 'Completed'
        ).length,
        byStatus: tasksByStatus as Record<TaskStatus, number>,
        byPriority: tasksByPriority as Record<string, number>,
      },
      contacts: {
        total: safeContacts.length,
        active: safeContacts.length, // All contacts are considered active for now
        inactive: 0, // No inactive contacts for now
        byCompany: contactsByCompany,
      },
      deals: {
        total: safeDeals.length,
        won: wonDeals.length,
        lost: lostDeals.length,
        totalValue: totalDealValue,
        averageDealSize: safeDeals.length > 0 ? totalDealValue / safeDeals.length : 0,
        byStage: dealsByStage as Record<DealStage, number>,
        pipelineValue: safeDeals
          .filter(deal => !['Closed Won', 'Closed Lost'].includes(deal.Stage))
          .reduce((sum, deal) => sum + (deal.Amount || 0), 0),
      },
      salesOrders: {
        total: safeSalesOrders.length,
        totalValue: totalSalesOrderValue,
        averageOrderValue: safeSalesOrders.length > 0 ? totalSalesOrderValue / safeSalesOrders.length : 0,
        byStatus: salesOrdersByStatus,
        byCountry: salesOrdersByCountry,
      },
      purchaseOrders: {
        total: safePurchaseOrders.length,
        totalValue: totalPurchaseOrderValue,
        averageOrderValue: safePurchaseOrders.length > 0 ? totalPurchaseOrderValue / safePurchaseOrders.length : 0,
        byStatus: purchaseOrdersByStatus,
        byVendor: purchaseOrdersByVendor,
      },
      invoices: {
        total: safeInvoices.length,
        totalValue: totalInvoiceValue,
        averageInvoiceValue: safeInvoices.length > 0 ? totalInvoiceValue / safeInvoices.length : 0,
        byStatus: invoicesByStatus,
        overdue: overdueInvoices.length,
        paid: paidInvoices.length,
      },
      customerKPIs,
    };
  }
);

// Dashboard specific selectors
export const selectDashboardData = createSelector(
  [selectCrmStats, selectLeads, selectDeals, selectTasks],
  (stats, leads, deals, tasks) => {
    // Ensure arrays are defined, fallback to empty arrays
    const safeLeads = leads || [];
    const safeDeals = deals || [];
    const safeTasks = tasks || [];

    // Top opportunities (deals by value) with safe property access
    const topOpportunities = [...safeDeals]
      .filter(deal => {
        const stage = deal?.Stage || '';
        return !['Closed Won', 'Closed Lost'].includes(stage);
      })
      .sort((a, b) => {
        const amountA = a?.Amount || 0;
        const amountB = b?.Amount || 0;
        return (typeof amountB === 'number' && !isNaN(amountB) ? amountB : 0) - 
               (typeof amountA === 'number' && !isNaN(amountA) ? amountA : 0);
      })
      .slice(0, 3)
      .map(deal => ({
        name: deal?.Deal_Name || 'Unnamed Deal',
        value: deal?.Amount || 0,
      }));

    // Recent activity (recent tasks) with safe property access
    const recentActivity = [...safeTasks]
      .sort((a, b) => {
        const dateA = a?.Created_Time ? new Date(a.Created_Time).getTime() : 0;
        const dateB = b?.Created_Time ? new Date(b.Created_Time).getTime() : 0;
        return dateB - dateA;
      })
      .slice(0, 3)
      .map(task => ({
        who: task?.Owner?.name || 'Unknown',
        what: task?.Subject || 'No subject',
        when: task?.Created_Time ? getTimeAgo(task.Created_Time) : 'Unknown',
      }));

    // Pipeline distribution
    const pipelineStages = [
      { label: 'Prospecting', value: stats.deals.byStage['Prospecting'] || 0, color: '#3AA0FF' },
      { label: 'Qualified', value: stats.deals.byStage['Qualification'] || 0, color: '#10B981' },
      { label: 'Proposal', value: stats.deals.byStage['Proposal'] || 0, color: '#F59E0B' },
      { label: 'Negotiation', value: stats.deals.byStage['Negotiation'] || 0, color: '#6366F1' },
      { label: 'Closed Won', value: stats.deals.won, color: '#22C55E' },
      { label: 'Closed Lost', value: stats.deals.lost, color: '#EF4444' },
    ];

    // Lead sources distribution
    const leadSources = Object.entries(stats.leads.bySource)
      .map(([source, count]) => ({
        label: source,
        value: count,
        color: getSourceColor(source),
      }))
      .sort((a, b) => b.value - a.value);

    // Leads trend (mock data for now - could be calculated from historical data)
    const leadsTrend = [60, 62, 68, 70, 76, 84]; // This would come from historical data

    return {
      // KPIs with safe calculations
      leads: stats.leads.total || 0,
      opportunities: stats.deals.total || 0,
      wonDeals: stats.deals.won || 0,
      conversionPct: stats.leads.total > 0 ? Math.round(((stats.leads.converted || 0) / stats.leads.total) * 100) : 0,
      
      // Charts and visualizations
      leadsTrend,
      pipeline: pipelineStages,
      sourceDist: leadSources,
      topOpps: topOpportunities,
      recent: recentActivity,
    };
  }
);

// Helper functions
function getTimeAgo(dateString: string): string {
  const now = new Date();
  const date = new Date(dateString);
  const diffInHours = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60));
  
  if (diffInHours < 1) return 'now';
  if (diffInHours < 24) return `${diffInHours}h`;
  const diffInDays = Math.floor(diffInHours / 24);
  return `${diffInDays}d`;
}

function getSourceColor(source: string): string {
  // Define a comprehensive color palette with distinct colors for sources
  const colorPalette = [
    '#3B82F6', // Bright Blue
    '#8B5CF6', // Purple
    '#06B6D4', // Cyan
    '#F59E0B', // Amber
    '#10B981', // Emerald
    '#F97316', // Orange
    '#22C55E', // Green
    '#84CC16', // Lime
    '#14B8A6', // Teal
    '#059669', // Dark Green
    '#EF4444', // Red
    '#DC2626', // Dark Red
    '#991B1B', // Darker Red
    '#9CA3AF', // Gray
    '#EC4899', // Pink
    '#8B5A2B', // Brown
    '#B91C1C', // Lost Red
    '#16A34A', // Success Green
    '#6366F1', // Indigo
    '#7C3AED', // Violet
    '#0891B2', // Sky Blue
    '#CA8A04', // Gold
    '#1F2937', // Dark Gray
    '#BE185D', // Rose
    '#0D9488', // Emerald Dark
    '#7C2D12', // Brown Dark
    '#1E40AF', // Blue Dark
    '#C2410C', // Orange Dark
    '#9333EA', // Purple Dark
    '#059669', // Green Dark
    '#DC2626', // Hot Red
    '#F97316', // Warm Orange
    '#6B7280', // Cold Gray
    '#EF4444', // Error Red
    '#10B981', // Success Green
    '#F59E0B', // Warning Orange
    '#3B82F6', // Info Blue
    '#0077B5', // LinkedIn Blue
    '#1877F2', // Facebook Blue
    '#1DA1F2', // Twitter Blue
    '#E4405F', // Instagram Pink
    '#FF0000', // YouTube Red
  ];

  // Create a consistent hash from the source string
  let hash = 0;
  const normalizedSource = source.toLowerCase().trim();
  for (let i = 0; i < normalizedSource.length; i++) {
    const char = normalizedSource.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash; // Convert to 32-bit integer
  }
  
  // Ensure positive index and get color from palette
  const colorIndex = Math.abs(hash) % colorPalette.length;
  return colorPalette[colorIndex];
}

// Loading state selectors
export const selectIsAnyLoading = createSelector(
  [selectCrmLoading],
  (loading) => Object.values(loading).some(Boolean)
);

export const selectHasAnyError = createSelector(
  [selectCrmErrors],
  (errors) => Object.values(errors).some(error => error !== null)
);

