import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { zohoBooksAPI } from '../services/zohoBooksAPI';
import type {
  ZohoBooksDashboardState,
  ZohoBooksContact,
  ZohoBooksInvoice,
  ZohoBooksExpense,
  ZohoBooksSalesOrder,
  ZohoBooksPurchaseOrder,
  ZohoBooksBill,
  ZohoBooksKPIData,
} from '../types/ZohoBooksTypes';

// Initial state
const initialState: ZohoBooksDashboardState = {
  contacts: [],
  invoices: [],
  expenses: [],
  salesOrders: [],
  purchaseOrders: [],
  bills: [],
  kpiData: {
    totalCustomers: 0,
    totalVendors: 0,
    totalInvoices: 0,
    totalExpenses: 0,
    totalSalesOrders: 0,
    totalPurchaseOrders: 0,
    totalBills: 0,
    outstandingReceivables: 0,
    outstandingPayables: 0,
    totalRevenue: 0,
    totalExpensesAmount: 0,
  },
  loading: false,
  error: null,
  lastUpdated: null,
};

// Helper function to calculate KPI data
const calculateKPIData = (
  contacts: ZohoBooksContact[],
  invoices: ZohoBooksInvoice[],
  expenses: ZohoBooksExpense[],
  salesOrders: ZohoBooksSalesOrder[],
  purchaseOrders: ZohoBooksPurchaseOrder[],
  bills: ZohoBooksBill[]
): ZohoBooksKPIData => {
  // Calculate totals
  const totalCustomers = contacts.filter(c => c.contact_type === 'customer').length;
  const totalVendors = contacts.filter(c => c.contact_type === 'vendor').length;
  const totalInvoices = invoices.length;
  const totalExpenses = expenses.length;
  const totalSalesOrders = salesOrders.length;
  const totalPurchaseOrders = purchaseOrders.length;
  const totalBills = bills.length;

  // Calculate financial metrics
  const outstandingReceivables = invoices
    .filter(inv => inv.status === 'sent' || inv.status === 'overdue')
    .reduce((sum, inv) => sum + inv.balance, 0);

  const outstandingPayables = bills
    .filter(bill => bill.status === 'open' || bill.status === 'overdue')
    .reduce((sum, bill) => sum + bill.balance, 0);

  const totalRevenue = invoices
    .filter(inv => inv.status === 'paid')
    .reduce((sum, inv) => sum + inv.total, 0);

  const totalExpensesAmount = expenses.reduce((sum, exp) => sum + exp.total, 0);

  return {
    totalCustomers,
    totalVendors,
    totalInvoices,
    totalExpenses,
    totalSalesOrders,
    totalPurchaseOrders,
    totalBills,
    outstandingReceivables,
    outstandingPayables,
    totalRevenue,
    totalExpensesAmount,
  };
};

// Async thunks
export const fetchZohoBooksData = createAsyncThunk(
  'zohoBooks/fetchAllData',
  async (_, { rejectWithValue }) => {
    try {
      const data = await zohoBooksAPI.getAllData();
      return data;
    } catch (error: any) {
      return rejectWithValue(error.message || 'Failed to fetch Zoho Books data');
    }
  }
);

export const fetchZohoBooksContacts = createAsyncThunk(
  'zohoBooks/fetchContacts',
  async (_, { rejectWithValue }) => {
    try {
      const response = await zohoBooksAPI.getContacts();
      return response.data.data;
    } catch (error: any) {
      return rejectWithValue(error.message || 'Failed to fetch contacts');
    }
  }
);

export const fetchZohoBooksInvoices = createAsyncThunk(
  'zohoBooks/fetchInvoices',
  async (_, { rejectWithValue }) => {
    try {
      const response = await zohoBooksAPI.getInvoices();
      return response.data.data;
    } catch (error: any) {
      return rejectWithValue(error.message || 'Failed to fetch invoices');
    }
  }
);

export const fetchZohoBooksExpenses = createAsyncThunk(
  'zohoBooks/fetchExpenses',
  async (_, { rejectWithValue }) => {
    try {
      const response = await zohoBooksAPI.getExpenses();
      return response.data.data;
    } catch (error: any) {
      return rejectWithValue(error.message || 'Failed to fetch expenses');
    }
  }
);

// Slice
const zohoBooksSlice = createSlice({
  name: 'zohoBooks',
  initialState,
  reducers: {
    clearError: (state) => {
      state.error = null;
    },
    resetState: () => initialState,
  },
  extraReducers: (builder) => {
    builder
      // Fetch all data
      .addCase(fetchZohoBooksData.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchZohoBooksData.fulfilled, (state, action) => {
        state.loading = false;
        state.contacts = action.payload.contacts;
        state.invoices = action.payload.invoices;
        state.expenses = action.payload.expenses;
        state.salesOrders = action.payload.salesOrders;
        state.purchaseOrders = action.payload.purchaseOrders;
        state.bills = action.payload.bills;
        
        // Calculate KPI data
        state.kpiData = calculateKPIData(
          action.payload.contacts,
          action.payload.invoices,
          action.payload.expenses,
          action.payload.salesOrders,
          action.payload.purchaseOrders,
          action.payload.bills
        );
        
        state.lastUpdated = new Date().toISOString();
        state.error = null;
      })
      .addCase(fetchZohoBooksData.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      })
      
      // Fetch contacts
      .addCase(fetchZohoBooksContacts.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchZohoBooksContacts.fulfilled, (state, action) => {
        state.loading = false;
        state.contacts = action.payload;
        state.error = null;
      })
      .addCase(fetchZohoBooksContacts.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      })
      
      // Fetch invoices
      .addCase(fetchZohoBooksInvoices.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchZohoBooksInvoices.fulfilled, (state, action) => {
        state.loading = false;
        state.invoices = action.payload;
        state.error = null;
      })
      .addCase(fetchZohoBooksInvoices.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      })
      
      // Fetch expenses
      .addCase(fetchZohoBooksExpenses.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchZohoBooksExpenses.fulfilled, (state, action) => {
        state.loading = false;
        state.expenses = action.payload;
        state.error = null;
      })
      .addCase(fetchZohoBooksExpenses.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload as string;
      });
  },
});

export const { clearError, resetState } = zohoBooksSlice.actions;
export default zohoBooksSlice.reducer;
