import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { salesforceCrmAPI } from '../services/salesforceCrmAPI';
import type { 
  SalesforceEvent,
  SalesforceLead, 
  SalesforceTask, 
  SalesforceAccount, 
  SalesforceOpportunity, 
  SalesforceStats,
  SalesforceSearchParams
} from '../types/SalesforceCrmTypes';

// State interface
export interface SalesforceCrmState {
  // Data
  events: SalesforceEvent[];
  leads: SalesforceLead[];
  tasks: SalesforceTask[];
  accounts: SalesforceAccount[];
  opportunities: SalesforceOpportunity[];
  
  // Loading states
  loading: {
    events: boolean;
    leads: boolean;
    tasks: boolean;
    accounts: boolean;
    opportunities: boolean;
    stats: boolean;
  };
  
  // Error states
  errors: {
    events: string | null;
    leads: string | null;
    tasks: string | null;
    accounts: string | null;
    opportunities: string | null;
    stats: string | null;
  };
  
  // Pagination
  pagination: {
    events: { page: number; count: number; moreRecords: boolean };
    leads: { page: number; count: number; moreRecords: boolean };
    tasks: { page: number; count: number; moreRecords: boolean };
    accounts: { page: number; count: number; moreRecords: boolean };
    opportunities: { page: number; count: number; moreRecords: boolean };
  };
  
  // Statistics
  stats: SalesforceStats | null;
  
  // Module counts
  counts: {
    events: number;
    leads: number;
    tasks: number;
    accounts: number;
    opportunities: number;
  } | null;
  
  // Last updated timestamps
  lastUpdated: {
    events: string | null;
    leads: string | null;
    tasks: string | null;
    accounts: string | null;
    opportunities: string | null;
    stats: string | null;
  };
}

// Initial state
const initialState: SalesforceCrmState = {
  events: [],
  leads: [],
  tasks: [],
  accounts: [],
  opportunities: [],
  loading: {
    events: false,
    leads: false,
    tasks: false,
    accounts: false,
    opportunities: false,
    stats: false,
  },
  errors: {
    events: null,
    leads: null,
    tasks: null,
    accounts: null,
    opportunities: null,
    stats: null,
  },
  pagination: {
    events: { page: 1, count: 0, moreRecords: false },
    leads: { page: 1, count: 0, moreRecords: false },
    tasks: { page: 1, count: 0, moreRecords: false },
    accounts: { page: 1, count: 0, moreRecords: false },
    opportunities: { page: 1, count: 0, moreRecords: false },
  },
  stats: null,
  counts: null,
  lastUpdated: {
    events: null,
    leads: null,
    tasks: null,
    accounts: null,
    opportunities: null,
    stats: null,
  },
};

// Async thunks for infinite scrolling
export const fetchSalesforceEvents = createAsyncThunk(
  'salesforceCrm/fetchEvents',
  async (params?: SalesforceSearchParams & { append?: boolean }) => {
    const response = await salesforceCrmAPI.getEvents(params);
    return { 
      data: response.data?.data?.data || [],
      count: response.data?.data?.count || 0,
      moreRecords: !response.data?.data?.metadata?.done,
      append: params?.append || false
    };
  }
);

export const fetchSalesforceLeads = createAsyncThunk(
  'salesforceCrm/fetchLeads',
  async (params?: SalesforceSearchParams & { append?: boolean }) => {
    const response = await salesforceCrmAPI.getLeads(params);
    return { 
      data: response.data?.data?.data || [],
      count: response.data?.data?.count || 0,
      moreRecords: !response.data?.data?.metadata?.done,
      append: params?.append || false
    };
  }
);

export const fetchSalesforceTasks = createAsyncThunk(
  'salesforceCrm/fetchTasks',
  async (params?: SalesforceSearchParams & { append?: boolean }) => {
    const response = await salesforceCrmAPI.getTasks(params);
    return { 
      data: response.data?.data?.data || [],
      count: response.data?.data?.count || 0,
      moreRecords: !response.data?.data?.metadata?.done,
      append: params?.append || false
    };
  }
);

export const fetchSalesforceAccounts = createAsyncThunk(
  'salesforceCrm/fetchAccounts',
  async (params?: SalesforceSearchParams & { append?: boolean }) => {
    const response = await salesforceCrmAPI.getAccounts(params);
    return { 
      data: response.data?.data?.data || [],
      count: response.data?.data?.count || 0,
      moreRecords: !response.data?.data?.metadata?.done,
      append: params?.append || false
    };
  }
);

export const fetchSalesforceOpportunities = createAsyncThunk(
  'salesforceCrm/fetchOpportunities',
  async (params?: SalesforceSearchParams & { append?: boolean }) => {
    const response = await salesforceCrmAPI.getOpportunities(params);
    return { 
      data: response.data?.data?.data || [],
      count: response.data?.data?.count || 0,
      moreRecords: !response.data?.data?.metadata?.done,
      append: params?.append || false
    };
  }
);

// Fetch Salesforce CRM counts
export const fetchSalesforceCrmCounts = createAsyncThunk(
  'salesforceCrm/fetchCounts',
  async () => {
    const response = await salesforceCrmAPI.getSalesforceCrmCounts();
    return response.data || {
      events: { count: 0, success: false },
      leads: { count: 0, success: false },
      tasks: { count: 0, success: false },
      accounts: { count: 0, success: false },
      opportunities: { count: 0, success: false },
    };
  }
);

// Fetch all Salesforce CRM data
export const fetchAllSalesforceCrmData = createAsyncThunk(
  'salesforceCrm/fetchAllData',
  async (params?: SalesforceSearchParams) => {
    const [
      eventsResponse, 
      leadsResponse, 
      tasksResponse, 
      accountsResponse,
      opportunitiesResponse
    ] = await Promise.all([
      salesforceCrmAPI.getEvents(params),
      salesforceCrmAPI.getLeads(params),
      salesforceCrmAPI.getTasks(params),
      salesforceCrmAPI.getAccounts(params),
      salesforceCrmAPI.getOpportunities(params),
    ]);
    
    return {
      events: {
        data: eventsResponse.data?.data?.data || [],
        count: eventsResponse.data?.data?.count || 0,
        moreRecords: !eventsResponse.data?.data?.metadata?.done
      },
      leads: {
        data: leadsResponse.data?.data?.data || [],
        count: leadsResponse.data?.data?.count || 0,
        moreRecords: !leadsResponse.data?.data?.metadata?.done
      },
      tasks: {
        data: tasksResponse.data?.data?.data || [],
        count: tasksResponse.data?.data?.count || 0,
        moreRecords: !tasksResponse.data?.data?.metadata?.done
      },
      accounts: {
        data: accountsResponse.data?.data?.data || [],
        count: accountsResponse.data?.data?.count || 0,
        moreRecords: !accountsResponse.data?.data?.metadata?.done
      },
      opportunities: {
        data: opportunitiesResponse.data?.data?.data || [],
        count: opportunitiesResponse.data?.data?.count || 0,
        moreRecords: !opportunitiesResponse.data?.data?.metadata?.done
      },
    };
  }
);

// Slice
const salesforceCrmSlice = createSlice({
  name: 'salesforceCrm',
  initialState,
  reducers: {
    clearErrors: (state) => {
      state.errors = {
        events: null,
        leads: null,
        tasks: null,
        accounts: null,
        opportunities: null,
        stats: null,
      };
    },
    clearData: (state) => {
      state.events = [];
      state.leads = [];
      state.tasks = [];
      state.accounts = [];
      state.opportunities = [];
      state.stats = null;
    },
    // Reset pagination for specific data types
    resetEventsPagination: (state) => {
      state.pagination.events = { page: 1, count: 0, moreRecords: false };
      state.events = [];
    },
    resetLeadsPagination: (state) => {
      state.pagination.leads = { page: 1, count: 0, moreRecords: false };
      state.leads = [];
    },
    resetTasksPagination: (state) => {
      state.pagination.tasks = { page: 1, count: 0, moreRecords: false };
      state.tasks = [];
    },
    resetAccountsPagination: (state) => {
      state.pagination.accounts = { page: 1, count: 0, moreRecords: false };
      state.accounts = [];
    },
    resetOpportunitiesPagination: (state) => {
      state.pagination.opportunities = { page: 1, count: 0, moreRecords: false };
      state.opportunities = [];
    },
  },
  extraReducers: (builder) => {
    // Fetch events
    builder
      .addCase(fetchSalesforceEvents.pending, (state) => {
        state.loading.events = true;
        state.errors.events = null;
      })
      .addCase(fetchSalesforceEvents.fulfilled, (state, action) => {
        state.loading.events = false;
        const { data, count, moreRecords, append } = action.payload;
        
        if (append) {
          // Append new data for infinite scrolling
          state.events = [...state.events, ...data];
        } else {
          // Replace data for initial load or refresh
          state.events = data;
        }
        
        state.pagination.events = { 
          page: append ? state.pagination.events.page + 1 : 1, 
          count, 
          moreRecords 
        };
        state.lastUpdated.events = new Date().toISOString();
      })
      .addCase(fetchSalesforceEvents.rejected, (state, action) => {
        state.loading.events = false;
        state.errors.events = action.error.message || 'Failed to fetch events';
      })
      
      // Fetch leads
      .addCase(fetchSalesforceLeads.pending, (state) => {
        state.loading.leads = true;
        state.errors.leads = null;
      })
      .addCase(fetchSalesforceLeads.fulfilled, (state, action) => {
        state.loading.leads = false;
        const { data, count, moreRecords, append } = action.payload;
        
        if (append) {
          state.leads = [...state.leads, ...data];
        } else {
          state.leads = data;
        }
        
        state.pagination.leads = { 
          page: append ? state.pagination.leads.page + 1 : 1, 
          count, 
          moreRecords 
        };
        state.lastUpdated.leads = new Date().toISOString();
      })
      .addCase(fetchSalesforceLeads.rejected, (state, action) => {
        state.loading.leads = false;
        state.errors.leads = action.error.message || 'Failed to fetch leads';
      })
      
      // Fetch tasks
      .addCase(fetchSalesforceTasks.pending, (state) => {
        state.loading.tasks = true;
        state.errors.tasks = null;
      })
      .addCase(fetchSalesforceTasks.fulfilled, (state, action) => {
        state.loading.tasks = false;
        const { data, count, moreRecords, append } = action.payload;
        
        if (append) {
          state.tasks = [...state.tasks, ...data];
        } else {
          state.tasks = data;
        }
        
        state.pagination.tasks = { 
          page: append ? state.pagination.tasks.page + 1 : 1, 
          count, 
          moreRecords 
        };
        state.lastUpdated.tasks = new Date().toISOString();
      })
      .addCase(fetchSalesforceTasks.rejected, (state, action) => {
        state.loading.tasks = false;
        state.errors.tasks = action.error.message || 'Failed to fetch tasks';
      })
      
      // Fetch accounts
      .addCase(fetchSalesforceAccounts.pending, (state) => {
        state.loading.accounts = true;
        state.errors.accounts = null;
      })
      .addCase(fetchSalesforceAccounts.fulfilled, (state, action) => {
        state.loading.accounts = false;
        const { data, count, moreRecords, append } = action.payload;
        
        if (append) {
          state.accounts = [...state.accounts, ...data];
        } else {
          state.accounts = data;
        }
        
        state.pagination.accounts = { 
          page: append ? state.pagination.accounts.page + 1 : 1, 
          count, 
          moreRecords 
        };
        state.lastUpdated.accounts = new Date().toISOString();
      })
      .addCase(fetchSalesforceAccounts.rejected, (state, action) => {
        state.loading.accounts = false;
        state.errors.accounts = action.error.message || 'Failed to fetch accounts';
      })
      
      // Fetch opportunities
      .addCase(fetchSalesforceOpportunities.pending, (state) => {
        state.loading.opportunities = true;
        state.errors.opportunities = null;
      })
      .addCase(fetchSalesforceOpportunities.fulfilled, (state, action) => {
        state.loading.opportunities = false;
        const { data, count, moreRecords, append } = action.payload;
        
        if (append) {
          state.opportunities = [...state.opportunities, ...data];
        } else {
          state.opportunities = data;
        }
        
        state.pagination.opportunities = { 
          page: append ? state.pagination.opportunities.page + 1 : 1, 
          count, 
          moreRecords 
        };
        state.lastUpdated.opportunities = new Date().toISOString();
      })
      .addCase(fetchSalesforceOpportunities.rejected, (state, action) => {
        state.loading.opportunities = false;
        state.errors.opportunities = action.error.message || 'Failed to fetch opportunities';
      })
      
      // Fetch all Salesforce CRM data
      .addCase(fetchAllSalesforceCrmData.pending, (state) => {
        state.loading.events = true;
        state.loading.leads = true;
        state.loading.tasks = true;
        state.loading.accounts = true;
        state.loading.opportunities = true;
        state.errors.events = null;
        state.errors.leads = null;
        state.errors.tasks = null;
        state.errors.accounts = null;
        state.errors.opportunities = null;
      })
      .addCase(fetchAllSalesforceCrmData.fulfilled, (state, action) => {
        const { events, leads, tasks, accounts, opportunities } = action.payload;
        
        state.loading.events = false;
        state.loading.leads = false;
        state.loading.tasks = false;
        state.loading.accounts = false;
        state.loading.opportunities = false;
        
        state.events = events.data;
        state.leads = leads.data;
        state.tasks = tasks.data;
        state.accounts = accounts.data;
        state.opportunities = opportunities.data;
        
        state.pagination.events = { page: 1, count: events.count, moreRecords: events.moreRecords };
        state.pagination.leads = { page: 1, count: leads.count, moreRecords: leads.moreRecords };
        state.pagination.tasks = { page: 1, count: tasks.count, moreRecords: tasks.moreRecords };
        state.pagination.accounts = { page: 1, count: accounts.count, moreRecords: accounts.moreRecords };
        state.pagination.opportunities = { page: 1, count: opportunities.count, moreRecords: opportunities.moreRecords };
        
        const now = new Date().toISOString();
        state.lastUpdated.events = now;
        state.lastUpdated.leads = now;
        state.lastUpdated.tasks = now;
        state.lastUpdated.accounts = now;
        state.lastUpdated.opportunities = now;
      })
      .addCase(fetchAllSalesforceCrmData.rejected, (state, action) => {
        state.loading.events = false;
        state.loading.leads = false;
        state.loading.tasks = false;
        state.loading.accounts = false;
        state.loading.opportunities = false;
        
        const errorMessage = action.error.message || 'Failed to fetch Salesforce CRM data';
        state.errors.events = errorMessage;
        state.errors.leads = errorMessage;
        state.errors.tasks = errorMessage;
        state.errors.accounts = errorMessage;
        state.errors.opportunities = errorMessage;
      })
      
      // Fetch Salesforce CRM counts
      .addCase(fetchSalesforceCrmCounts.pending, (state) => {
        // No loading state needed for counts as it's fetched in background
      })
      .addCase(fetchSalesforceCrmCounts.fulfilled, (state, action) => {
        const data = action.payload as any;
        state.counts = {
          events: data.events?.count || 0,
          leads: data.leads?.count || 0,
          tasks: data.tasks?.count || 0,
          accounts: data.accounts?.count || 0,
          opportunities: data.opportunities?.count || 0,
        };
      })
      .addCase(fetchSalesforceCrmCounts.rejected, (state) => {
        // Keep existing counts on error
        console.warn('Failed to fetch Salesforce CRM counts');
      });
  },
});

export const {
  clearErrors,
  clearData,
  resetEventsPagination,
  resetLeadsPagination,
  resetTasksPagination,
  resetAccountsPagination,
  resetOpportunitiesPagination,
} = salesforceCrmSlice.actions;

export default salesforceCrmSlice.reducer;

