
import React, { useState, useMemo } from 'react';
import { Association, Balance, Operation, OperationType } from '../types';
import { api } from '../api';
import Header from './Header';
import BalanceCard from './BalanceCard';
import OperationsChart from './OperationsChart';
import OperationsTable from './OperationsTable';
import AddOperationModal from './AddOperationModal';
import AddBalanceModal from './AddBalanceModal';
import { format, subDays, startOfMonth, endOfMonth } from 'date-fns';

interface DashboardProps {
    association: Association;
    onLogout: () => void;
    onUpdateAssociation: (association: Association) => void;
}

const Dashboard: React.FC<DashboardProps> = ({ association, onLogout, onUpdateAssociation }) => {
    const today = new Date();
    const [dateRange, setDateRange] = useState<{ start: Date, end: Date }>({ start: startOfMonth(today), end: endOfMonth(today) });
    const [selectedBalanceId, setSelectedBalanceId] = useState<string | null>(association.balances[0]?.id ?? null);
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [isAddBalanceModalOpen, setIsAddBalanceModalOpen] = useState(false);

    const [balanceToEdit, setBalanceToEdit] = useState<Balance | null>(null);
    const [draggedBalanceIndex, setDraggedBalanceIndex] = useState<number | null>(null);

    const [operationToEdit, setOperationToEdit] = useState<Operation | null>(null);
    const scrollContainerRef = React.useRef<HTMLDivElement>(null);

    const scroll = (direction: 'left' | 'right') => {
        if (scrollContainerRef.current) {
            const scrollAmount = 320;
            const newScrollLeft = scrollContainerRef.current.scrollLeft + (direction === 'right' ? scrollAmount : -scrollAmount);
            scrollContainerRef.current.scrollTo({
                left: newScrollLeft,
                behavior: 'smooth'
            });
        }
    };

    const filteredOperations = useMemo(() => {
        return association.operations.filter(op => {
            const opDate = new Date(op.date);
            return opDate >= dateRange.start && opDate <= dateRange.end;
        });
    }, [association.operations, dateRange]);

    const selectedBalance = useMemo(() => {
        return association.balances.find(b => b.id === selectedBalanceId) ?? null;
    }, [association.balances, selectedBalanceId]);

    const operationsForSelectedBalance = useMemo(() => {
        return filteredOperations.filter(op => op.balanceId === selectedBalanceId);
    }, [filteredOperations, selectedBalanceId]);

    const incomesForSelectedBalance = operationsForSelectedBalance.filter(op => op.type === OperationType.INCOME);
    const expensesForSelectedBalance = operationsForSelectedBalance.filter(op => op.type === OperationType.EXPENSE);

    const handleAddOperation = async (newOperationData: Omit<Operation, 'id'>) => {
        try {
            const newOperation = await api.createOperation({
                ...newOperationData,
                balance_id: newOperationData.balanceId,
                date: newOperationData.date,
            });

            const updatedAssociation = {
                ...association,
                operations: [...association.operations, newOperation]
            };
            onUpdateAssociation(updatedAssociation);
            setIsModalOpen(false);
        } catch (error) {
            console.error("Failed to add operation", error);
            alert("Failed to add operation");
        }
    };

    const handleUpdateOperation = async (updatedOperation: Operation) => {
        try {
            const result = await api.updateOperation({
                ...updatedOperation,
                balanceId: updatedOperation.balanceId,
            });

            const updatedAssociation = {
                ...association,
                operations: association.operations.map(op => op.id === result.id ? result : op)
            };
            onUpdateAssociation(updatedAssociation);
            setIsModalOpen(false);
            setOperationToEdit(null);
        } catch (error) {
            console.error("Failed to update operation", error);
            alert("Failed to update operation");
        }
    };

    const handleDeleteOperation = async (operationId: string) => {
        if (window.confirm('Are you sure you want to delete this operation?')) {
            try {
                await api.deleteOperation(operationId);
                const updatedAssociation = {
                    ...association,
                    operations: association.operations.filter(op => op.id !== operationId)
                };
                onUpdateAssociation(updatedAssociation);
            } catch (error) {
                console.error("Failed to delete operation", error);
                alert("Failed to delete operation");
            }
        }
    };

    const handleEditOperation = (operation: Operation) => {
        setOperationToEdit(operation);
        setIsModalOpen(true);
    };

    const handleCloseModal = () => {
        setIsModalOpen(false);
        setOperationToEdit(null);
    };

    const handleAddBalance = async (newBalanceData: Omit<Balance, 'id'>) => {
        try {
            const newBalance = await api.addBalance(newBalanceData.name, newBalanceData.initialAmount, association.id);
            const updatedAssociation = {
                ...association,
                balances: [...association.balances, newBalance]
            };
            onUpdateAssociation(updatedAssociation);
            setIsAddBalanceModalOpen(false);
            setSelectedBalanceId(newBalance.id);
        } catch (error) {
            console.error("Failed to add balance", error);
            alert("Failed to add balance");
        }
    };

    const handleEditBalance = (balance: Balance) => {
        setBalanceToEdit(balance);
        setIsAddBalanceModalOpen(true);
    };

    const handleDeleteBalance = async (balanceId: string) => {
        if (window.confirm('Are you sure you want to delete this balance? All associated operations will be lost.')) {
            try {
                await api.deleteBalance(balanceId);
                const updatedAssociation = {
                    ...association,
                    balances: association.balances.filter(b => b.id !== balanceId)
                };
                onUpdateAssociation(updatedAssociation);
                if (selectedBalanceId === balanceId) {
                    setSelectedBalanceId(updatedAssociation.balances[0]?.id ?? null);
                }
            } catch (error) {
                console.error("Failed to delete balance", error);
                alert("Failed to delete balance");
            }
        }
    };

    const handleUpdateBalance = async (updatedBalance: Balance) => {
        try {
            const result = await api.updateBalance(updatedBalance);
            const updatedAssociation = {
                ...association,
                balances: association.balances.map(b => b.id === result.id ? result : b)
            };
            onUpdateAssociation(updatedAssociation);
            setIsAddBalanceModalOpen(false);
            setBalanceToEdit(null);
        } catch (error) {
            console.error("Failed to update balance", error);
            alert("Failed to update balance");
        }
    };

    const handleDragStart = (index: number) => {
        setDraggedBalanceIndex(index);
    };

    const handleDragOver = (e: React.DragEvent) => {
        e.preventDefault();
    };

    const handleDrop = async (dropIndex: number) => {
        if (draggedBalanceIndex === null || draggedBalanceIndex === dropIndex) return;

        const newBalances = [...association.balances];
        const [draggedBalance] = newBalances.splice(draggedBalanceIndex, 1);
        newBalances.splice(dropIndex, 0, draggedBalance);

        const updatedBalances = newBalances.map((b, index) => ({
            ...b,
            position: index
        }));

        onUpdateAssociation({
            ...association,
            balances: updatedBalances
        });

        try {
            await Promise.all(updatedBalances.map(b => api.updateBalance(b)));
        } catch (error) {
            console.error("Failed to update balance positions", error);
            alert("Failed to save new order");
        }
        setDraggedBalanceIndex(null);
    };

    return (
        <div className="min-h-screen bg-gray-50">
            {/* ... Header ... */}
            <Header
                associationName={association.name}
                onLogout={onLogout}
                dateRange={dateRange}
                setDateRange={setDateRange}
                operations={association.operations}
                balances={association.balances}
            />
            <main className="p-4 sm:p-6 lg:p-8 max-w-7xl mx-auto">
                <div className="flex items-center justify-between mb-6">
                    <h2 className="text-2xl font-bold text-gray-800">Balances</h2>
                    <div className="flex space-x-3">
                        <button
                            onClick={() => {
                                setBalanceToEdit(null);
                                setIsAddBalanceModalOpen(true);
                            }}
                            className="bg-white text-gray-800 border border-gray-300 px-4 py-2 rounded-lg font-semibold hover:bg-gray-50 transition flex items-center space-x-2"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                                <path fillRule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clipRule="evenodd" />
                            </svg>
                            <span>Add Balance</span>
                        </button>
                        <button
                            onClick={() => setIsModalOpen(true)}
                            className="bg-gray-800 text-white px-4 py-2 rounded-lg font-semibold hover:bg-gray-900 transition flex items-center space-x-2"
                        >
                            <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor"><path fillRule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clipRule="evenodd" /></svg>
                            <span>Add Operation</span>
                        </button>
                    </div>
                </div>

                <div className="relative group">
                    <button
                        onClick={() => scroll('left')}
                        className="absolute left-0 top-1/2 -translate-y-1/2 -ml-4 z-10 bg-white rounded-full p-2 shadow-lg border border-gray-200 text-gray-600 hover:text-gray-900 hover:bg-gray-50 transition opacity-0 group-hover:opacity-100 focus:opacity-100"
                        aria-label="Scroll left"
                    >
                        <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
                        </svg>
                    </button>

                    <div
                        ref={scrollContainerRef}
                        className="p-2 flex space-x-6 pb-6 overflow-x-auto snap-x snap-mandatory scrollbar-none"
                        style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
                    >
                        {association.balances
                            .sort((a, b) => (a.position - b.position))
                            .map((balance, index) => (
                                <div
                                    key={balance.id}
                                    className="snap-start flex-shrink-0 w-80"
                                    draggable
                                    onDragStart={() => handleDragStart(index)}
                                    onDragOver={handleDragOver}
                                    onDrop={() => handleDrop(index)}
                                >
                                    <BalanceCard
                                        balance={balance}
                                        operations={filteredOperations.filter(op => op.balanceId === balance.id)}
                                        isSelected={selectedBalanceId === balance.id}
                                        onClick={() => setSelectedBalanceId(balance.id)}
                                        onEdit={handleEditBalance}
                                        onDelete={handleDeleteBalance}
                                    />
                                </div>
                            ))}
                    </div>

                    <button
                        onClick={() => scroll('right')}
                        className="absolute right-0 top-1/2 -translate-y-1/2 -mr-4 z-10 bg-white rounded-full p-2 shadow-lg border border-gray-200 text-gray-600 hover:text-gray-900 hover:bg-gray-50 transition opacity-0 group-hover:opacity-100 focus:opacity-100"
                        aria-label="Scroll right"
                    >
                        <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                        </svg>
                    </button>
                </div>

                <div className="grid grid-cols-1 lg:grid-cols-3 gap-8 mt-8">
                    <div className="lg:col-span-3 bg-white p-6 rounded-xl shadow-md border border-gray-200">
                        <h3 className="text-xl font-semibold mb-4 text-gray-800">Balances Variation</h3>
                        <OperationsChart
                            balances={association.balances}
                            allOperations={association.operations}
                            dateRange={dateRange}
                        />
                    </div>

                    {selectedBalance && (
                        <>
                            <div className="lg:col-span-3 bg-white p-6 rounded-xl shadow-md border border-gray-200">
                                <h3 className="text-xl font-semibold mb-4 text-gray-800">
                                    Operations for <span className="text-gray-900 font-bold">{selectedBalance.name}</span>
                                </h3>
                                <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
                                    <OperationsTable
                                        title="Income"
                                        operations={incomesForSelectedBalance}
                                        onEdit={handleEditOperation}
                                        onDelete={handleDeleteOperation}
                                    />
                                    <OperationsTable
                                        title="Expenses"
                                        operations={expensesForSelectedBalance}
                                        onEdit={handleEditOperation}
                                        onDelete={handleDeleteOperation}
                                    />
                                </div>
                            </div>
                        </>
                    )}
                </div>

            </main>
            <AddOperationModal
                isOpen={isModalOpen}
                onClose={handleCloseModal}
                onAddOperation={handleAddOperation}
                onUpdateOperation={handleUpdateOperation}
                operationToEdit={operationToEdit}
                balances={association.balances}
            />
            <AddBalanceModal
                isOpen={isAddBalanceModalOpen}
                onClose={() => {
                    setIsAddBalanceModalOpen(false);
                    setBalanceToEdit(null);
                }}
                onAddBalance={handleAddBalance}
                onUpdateBalance={handleUpdateBalance}
                balanceToEdit={balanceToEdit}
            />
        </div>
    );
};

export default Dashboard;
