import React, { useEffect, useState, useRef } from 'react';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import LineChartComponent from './Components/LineChartComponent';
import { io } from 'socket.io-client';

const MAX_POINTS = 20;
const COLORS = ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850'];
const TIME_RANGES = [
    { label: '1 минута', value: 60, interval: 3000 },
    { label: '5 минут', value: 300, interval: 15000 },
    { label: '30 минут', value: 1800, interval: 90000 },
    { label: '1 час', value: 3600, interval: 180000 },
    { label: '3 часа', value: 10800, interval: 540000 },
    { label: '6 часов', value: 21600, interval: 1080000 },
    { label: '12 часов', value: 43200, interval: 2160000 },
    { label: '24 часа', value: 86400, interval: 4320000 },
    { label: '2 дня', value: 172800, interval: 8640000 },
    { label: '7 дней', value: 604800, interval: 30240000 },
    { label: '30 дней', value: 2592000, interval: 129600000 },
    { label: '90 дней', value: 7776000, interval: 388800000 },
    { label: '6 месяцев', value: 15552000, interval: 777600000 },
    { label: '9 месяцев', value: 23328000, interval: 1166400000 },
    { label: '1 год', value: 31536000, interval: 1576800000 },
];

const PrometheusChart = ({ metricName }) => {
    const [chartData, setChartData] = useState({});
    const [selectedRange, setSelectedRange] = useState(TIME_RANGES[0]);
    const [startDate, setStartDate] = useState(new Date());
    const [endDate, setEndDate] = useState(new Date());
    const [useCustomRange, setUseCustomRange] = useState(false);
    const [selectedGraphRange, setSelectedGraphRange] = useState(null);
    const [filteredData, setFilteredData] = useState(null);
    const [connectionStatus, setConnectionStatus] = useState('disconnected');
    const intervalRef = useRef(null);
    const socketRef = useRef(null);

    const setupWebSocket = () => {
        const socket = io('http://192.168.2.39:3000/metrics-ws', {
            path: '/socket.io',
            transports: ['websocket'],
            reconnection: true,
            reconnectionAttempts: 5,
            reconnectionDelay: 1000,
        });

        socketRef.current = socket;

        socket.on('connect', () => {
            setConnectionStatus('connected');
            fetchData();
        });

        socket.on('disconnect', () => {
            setConnectionStatus('disconnected');
        });

        socket.on('connect_error', (err) => {
            setConnectionStatus('error');
        });

        socket.on('metrics-data', (response) => {
            processMetricsData(response);
        });

        return socket;
    };

    const calculateStep = (start, end) => {
        const range = end - start;
        if (range <= 3600) return 5;
        if (range <= 21600) return 30;
        if (range <= 86400) return 120;
        return 300;
    };

    const fetchData = () => {
        try {
            const now = Math.floor(Date.now() / 1000);
            let start = useCustomRange
                ? Math.floor(startDate.getTime() / 1000)
                : now - selectedRange.value;
            let end = useCustomRange
                ? Math.floor(endDate.getTime() / 1000)
                : now;

            // Проверка на корректность диапазона
            if (start >= end) {
                console.error('Invalid time range: start >= end');
                return;
            }

            const step = calculateStep(start, end);

            if (socketRef.current?.connected) {
                socketRef.current.emit('get-metrics', {
                    metric: metricName,
                    start,
                    end,
                    step
                });
            } else {
                console.error('WebSocket is not connected');
            }
        } catch (error) {
            console.error('Error in fetchData:', error);
        }
    };

    const processMetricsData = (response) => {
        const { metric, data } = response;
        if (metric !== metricName) return;

        let metrics = Array.isArray(data) ? data : [];
        let start, end;

        if (metrics.length === 0) {
            console.warn('Received empty metrics data');
            return;
        }

        if (useCustomRange) {
            start = Math.floor(startDate.getTime() / 1000);
            end = Math.floor(endDate.getTime() / 1000);
        } else {
            end = Math.floor(Date.now() / 1000);
            start = end - selectedRange.value;
        }

        const step = calculateStep(start, end);
        const range = end - start;

        // 1. Генерируем ВСЕ ожидаемые временные точки
        const timePoints = [];
        for (let t = start; t <= end; t += step) {
            const date = new Date(t * 1000);
            const formattedTime = range > 86400
                ? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
                : date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
            timePoints.push(formattedTime);
        }

        // 2. Создаем карту "время -> значение" для каждого инстанса
        const timeValueMap = {};
        metrics.forEach(m => {
            const date = new Date(m.timestamp);
            const formattedTime = range > 86400
                ? date.toLocaleString([], { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
                : date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });

            const key = m.instance;
            if (!timeValueMap[key]) timeValueMap[key] = {};
            timeValueMap[key][formattedTime] = m.value;
        });

        // 3. Строим финальные данные, гарантируя все временные точки
        const newChartData = {};
        Object.keys(timeValueMap).forEach(instance => {
            newChartData[instance] = timePoints.map(time => ({
                time,
                value: timeValueMap[instance][time] ?? null // null если данных нет
            }));
        });

        setChartData({ ...newChartData }); // Форсируем обновление
    };

    const interpolateData = (data, minPoints = 15) => {
        if (data.length >= minPoints) return data;

        const interpolatedData = [];
        for (let i = 0; i < data.length - 1; i++) {
            interpolatedData.push(data[i]);

            const currentPoint = data[i];
            const nextPoint = data[i + 1];
            const currentTime = new Date(currentPoint.time).getTime();
            const nextTime = new Date(nextPoint.time).getTime();
            const timeDiff = nextTime - currentTime;

            const steps = Math.ceil((minPoints - data.length) / (data.length - 1));
            for (let j = 1; j <= steps; j++) {
                const interpolatedTime = new Date(currentTime + (timeDiff * j) / (steps + 1)).toLocaleString();
                const interpolatedPoint = { time: interpolatedTime };

                Object.keys(currentPoint).forEach(key => {
                    if (key !== 'time') {
                        const currentValue = currentPoint[key];
                        const nextValue = nextPoint[key];
                        interpolatedPoint[key] = currentValue + ((nextValue - currentValue) * j) / (steps + 1);
                    }
                });

                interpolatedData.push(interpolatedPoint);
            }
        }

        interpolatedData.push(data[data.length - 1]);
        return interpolatedData.slice(0, minPoints);
    };

    const handleRangeChange = (event) => {
        const selectedValue = event.target.value;
        const range = TIME_RANGES.find(r => r.value === parseInt(selectedValue, 10));

        // Сбрасываем данные и состояние
        setChartData({});
        setFilteredData(null);
        setSelectedGraphRange(null);

        // Обновляем диапазон и даты
        setSelectedRange(range);
        setUseCustomRange(false);

        const now = new Date();
        setEndDate(now);
        setStartDate(new Date(now.getTime() - range.value * 1000));

        // Принудительно запрашиваем новые данные
        // Используем setTimeout для гарантированного обновления состояния перед запросом
        setTimeout(() => {
            fetchData();
        }, 0);
    };

    const handleCustomRangeChange = () => {
        // Сбрасываем данные и состояние
        setChartData({});
        setFilteredData(null);
        setSelectedGraphRange(null);

        setUseCustomRange(true);

        // Принудительно запрашиваем новые данные
        setTimeout(() => {
            fetchData();
        }, 0);
    };

    const handleResetZoom = () => {
        setSelectedGraphRange(null);
        setFilteredData(null);
        fetchData();
    };

    useEffect(() => {
        const socket = setupWebSocket();

        // Первоначальная загрузка данных
        fetchData();

        // Настраиваем интервал обновления
        const intervalId = setInterval(() => {
            fetchData();
        }, selectedRange.interval);

        intervalRef.current = intervalId;

        return () => {
            clearInterval(intervalRef.current);
            socket.disconnect();
        };
    }, [metricName, selectedRange.value]);

    useEffect(() => {
        // При изменении диапазона или дат перезапускаем интервал
        if (socketRef.current?.connected) {
            clearInterval(intervalRef.current);
            fetchData();

            intervalRef.current = setInterval(() => {
                fetchData();
            }, selectedRange.interval);
        }
    }, [selectedRange, useCustomRange, startDate, endDate, metricName]);

    useEffect(() => {
        if (selectedGraphRange) {
            const { startIndex, endIndex } = selectedGraphRange;
            const allTimes = Object.values(chartData)
                .flat()
                .map(point => point.time)
                .filter((time, index, self) => self.indexOf(time) === index);

            const data = allTimes.map(time => {
                const point = { time };
                Object.keys(chartData).forEach(key => {
                    const instanceData = chartData[key].find(p => p.time === time);
                    point[key] = instanceData ? instanceData.value : null;
                });
                return point;
            });

            const filtered = data.slice(startIndex, endIndex + 1);
            const interpolated = interpolateData(filtered, 15);
            setFilteredData(interpolated);
        } else {
            setFilteredData(null);
        }
    }, [selectedGraphRange, chartData]);

    if (!Object.keys(chartData).length) return <p>Loading...</p>;

    const allTimes = Object.values(chartData)
        .flat()
        .map(point => point.time)
        .filter((time, index, self) => self.indexOf(time) === index);

    const data = allTimes.map(time => {
        const point = { time };
        Object.keys(chartData).forEach(key => {
            const instanceData = chartData[key].find(p => p.time === time);
            point[key] = instanceData ? instanceData.value : null;
        });
        return point;
    });

    return (
        <div style={{
            backgroundColor: '#fff',
            borderRadius: '8px',
            padding: '20px',
            marginBottom: '20px',
            position: 'relative'
        }}>
            <div style={{
                position: 'absolute',
                top: '10px',
                right: '10px',
                padding: '5px 10px',
                borderRadius: '4px',
                backgroundColor: connectionStatus === 'connected' ? '#4CAF50' :
                    connectionStatus === 'error' ? '#F44336' : '#FFC107',
                color: 'white',
                fontSize: '12px'
            }}>
                {connectionStatus === 'connected' ? 'Online' :
                    connectionStatus === 'error' ? 'Connection Error' : 'Offline'}
            </div>
            {/* Заголовок графика */}
            <h3 style={{ marginTop: 0, color: '#333' }}>
            </h3>

            {/* Группа элементов управления */}
            <div style={{
                display: 'flex',
                flexWrap: 'wrap',
                gap: '15px',
                alignItems: 'center',
                marginBottom: '15px'
            }}>
                {/* Стандартные диапазоны */}
                <div style={{ flex: '1 1 200px', display: 'flex', gap: '10px', alignItems: 'flex-end' }}>
                    <div style={{ flex: '1' }}>
                        <label htmlFor="time-range" style={{
                            display: 'block',
                            marginBottom: '5px',
                            fontWeight: '500',
                            color: '#555'
                        }}>Стандартные диапазоны:</label>
                        <select
                            id="time-range"
                            value={selectedRange.value}
                            onChange={handleRangeChange}
                            style={{
                                width: '100%',
                                padding: '8px 12px',
                                borderRadius: '4px',
                                border: '1px solid #ddd',
                                color: "#333",
                                backgroundColor: '#f9f9f9'
                            }}
                        >
                            {TIME_RANGES.map(range => (
                                <option key={range.value} value={range.value}>{range.label}</option>
                            ))}
                        </select>
                    </div>

                    {/* Кнопка сброса */}
                    <button
                        onClick={handleResetZoom}
                        style={{
                            padding: '8px 16px',
                            backgroundColor: '#f0f0f0',
                            color: '#333',
                            border: '1px solid #ddd',
                            borderRadius: '4px',
                            cursor: 'pointer',
                            transition: 'all 0.2s',
                            height: '36px',
                            whiteSpace: 'nowrap'
                        }}
                        onMouseOver={(e) => e.target.style.backgroundColor = '#e0e0e0'}
                        onMouseOut={(e) => e.target.style.backgroundColor = '#f0f0f0'}
                    >
                        Сбросить
                    </button>
                </div>



                {/* Кастомный диапазон */}
                <div style={{ flex: '1 1 300px' }}>
                    <div style={{
                        marginBottom: '10px',
                        fontWeight: '500',
                        color: '#555'
                    }}>
                        Или укажите свой диапазон:
                    </div>
                    <div style={{
                        display: 'flex',
                        gap: '10px',
                        flexWrap: 'wrap'
                    }}>
                        <div style={{ flex: '1 1 200px' }}>
                            <DatePicker
                                selected={startDate}
                                onChange={(date) => setStartDate(date)}
                                showTimeSelect
                                timeFormat="HH:mm"
                                timeIntervals={15}
                                dateFormat="yyyy-MM-dd HH:mm"
                                placeholderText="Начальная дата"
                                customInput={
                                    <input style={{
                                        backgroundColor: '#f9f9f9',
                                        color: "#555",
                                        width: '100%',
                                        padding: '8px 12px',
                                        borderRadius: '4px',
                                        border: '1px solid #ddd'
                                    }} />
                                }
                            />
                        </div>
                        <div style={{ flex: '1 1 200px' }}>
                            <DatePicker
                                selected={endDate}
                                onChange={(date) => setEndDate(date)}
                                showTimeSelect
                                timeFormat="HH:mm"
                                timeIntervals={15}
                                dateFormat="yyyy-MM-dd HH:mm"
                                placeholderText="Конечная дата"
                                customInput={
                                    <input style={{
                                        backgroundColor: '#f9f9f9',
                                        color: "#555",
                                        width: '100%',
                                        padding: '8px 12px',
                                        borderRadius: '4px',
                                        border: '1px solid #ddd'
                                    }} />
                                }
                            />
                        </div>
                        <button
                            onClick={handleCustomRangeChange}
                            style={{
                                padding: '8px 16px',
                                backgroundColor: '#4a6baf',
                                color: 'white',
                                border: 'none',
                                borderRadius: '4px',
                                cursor: 'pointer',
                                transition: 'background-color 0.2s',
                                flex: '0 0 auto',
                                alignSelf: 'flex-end'
                            }}
                            onMouseOver={(e) => e.target.style.backgroundColor = '#3a5a9f'}
                            onMouseOut={(e) => e.target.style.backgroundColor = '#4a6baf'}
                        >
                            Применить
                        </button>
                    </div>
                </div>
            </div>

            {/* Индикатор текущего диапазона */}
            <div style={{
                margin: '10px 0',
                padding: '8px 12px',
                backgroundColor: '#f0f7ff',
                borderRadius: '4px',
                borderLeft: '3px solid #4a6baf'
            }}>
                Текущий диапазон: {useCustomRange
                    ? `${startDate.toLocaleString()} - ${endDate.toLocaleString()}`
                    : selectedRange.label}
            </div >

            {/* График */}
            <LineChartComponent
                chartData={chartData}
                metricName={metricName}
                colors={COLORS}
                description={metricName}
                onRangeSelect={setSelectedGraphRange}
                filteredData={filteredData}
            />
        </div>
    );
};

export default PrometheusChart;