import React, {useEffect, useState} from 'react';
import Chart from 'react-apexcharts';
import {ApexOptions} from 'apexcharts';
import apiFetch from '@wordpress/api-fetch';
import {getDate} from '@wordpress/date';
import { formatTimestamp } from '@givewp/admin/common';

/**
 * @since 4.4.0
 */
type TimeSeriesChartProps = {
    endpoint: string;
    amountFormatter: Intl.NumberFormat;
    title?: string;
};

/**
 * @since 4.4.0
 */
type Donation = {
    createdAt: string;
    amount: {
        value: string;
    };
};

/**
 * @since 4.4.0
 */
type DataPoint = {
    x: string;
    y: number;
};

/**
 * @since 4.4.0
 * Generates a range of dates around a target date for displaying a single donation graph.
 */
const getCenteredGraphRange = (targetDate: string) => {
    const result = [];
    const date = new Date(targetDate);

    for (let i = -3; i <= 3; i++) {
        const currentDate = new Date(date);
        currentDate.setDate(date.getDate() + i);
        result.push(currentDate.toISOString().split('T')[0]);
    }
    return result;
};

/**
 * @since 4.4.0
 */
const normalizeData = (donations: Donation[]): DataPoint[] => {
    const map = new Map<string, number>();

    // Group donations by date with sum amounts - fill missing dates with 0.
    donations.forEach((donation) => {
        const date = getDate(donation.createdAt);
        const amount = parseFloat(donation.amount.value);
        map.set(date.toISOString().split('T')[0], (map.get(date.toISOString().split('T')[0]) || 0) + amount);
    });

    // Set graph range & points for single donations.
    if (map.size === 1) {
        const donationDate = donations[0]?.createdAt.split(' ')[0];
        const graphRange = getCenteredGraphRange(donationDate);

        return graphRange.map((date) => ({
            x: date,
            y: map.get(date) || 0,
        }));
    }

    // Convert to sorted array of data points.
    return Array.from(map.entries())
        .map(([date, amount]) => ({
            x: date,
            y: amount,
        }))
        .sort((a, b) => a.x.localeCompare(b.x));
};

/**
 * @since 4.13.0 updated the date format
 * @since 4.4.0
 */
export default function TimeSeriesChart({endpoint, amountFormatter, title = ''}: TimeSeriesChartProps) {
    const [series, setSeries] = useState([{name: title, data: []}]);

    useEffect(() => {
        apiFetch<Donation[]>({path: endpoint}).then((data) => {
            const normalized = normalizeData(data);
            setSeries([{name: title, data: normalized}]);
        });
    }, [endpoint]);

    const options: ApexOptions = {
        chart: {
            type: 'area' as const,
            toolbar: {show: false},
            zoom: {enabled: false},
        },
        xaxis: {
            type: 'datetime',
            labels: {
                formatter: (val) => formatTimestamp(val, false),
            },
        },
        yaxis: {
            min: 0,
            labels: {
                formatter: (val) => amountFormatter.format(val),
            },
        },
        dataLabels: {enabled: false},
        stroke: {
            curve: 'smooth',
            width: 2,
            colors: ['#60a1e2'],
        },
        fill: {
            type: 'gradient',
            gradient: {
                shadeIntensity: 1,
                opacityFrom: 0.3,
                opacityTo: 0,
                stops: [0, 100],
            },
        },
        tooltip: {
            x: {
                format: 'MMM dd, yyyy',
            },
        },
    };

    return <Chart options={options} series={series} type="area" height="250" />;
}
