import moment from 'moment';
import {TestWrapper} from '@tryghost/admin-x-framework/test/test-utils';
import {beforeEach, describe, expect, it, vi} from 'vitest';
import {getExpectedDateRange, setupDateMocking, setupStatsAppMocks} from '../../utils/test-helpers';
import {renderHook} from '@testing-library/react';
import {useTopPostsStatsWithRange} from '@hooks/use-top-posts-stats-with-range';

vi.mock('@tryghost/admin-x-framework/api/stats');
vi.mock('@src/providers/global-data-provider');
vi.mock('@tryghost/shade/app', () => ({
    formatQueryDate: vi.fn(),
    getRangeDates: vi.fn()
}));

const mockUseTopPostsStats = vi.mocked(await import('@tryghost/admin-x-framework/api/stats')).useTopPostsStats;
const {formatQueryDate, getRangeDates} = await import('@tryghost/shade/app');
const mockFormatQueryDate = vi.mocked(formatQueryDate);
const mockGetRangeDates = vi.mocked(getRangeDates);

describe('useTopPostsStatsWithRange', () => {
    let mocks: ReturnType<typeof setupStatsAppMocks>;
    let dateMocking: ReturnType<typeof setupDateMocking>;

    beforeEach(() => {
        vi.clearAllMocks();
        mocks = setupStatsAppMocks();
        dateMocking = setupDateMocking();

        // Mock the date functions with consistent behavior
        mockGetRangeDates.mockImplementation((range: number) => {
            const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(range);
            return {
                startDate: moment.utc(expectedDateFrom).startOf('day'),
                endDate: moment.utc(expectedDateTo).startOf('day'),
                timezone: 'UTC'
            };
        });

        mockFormatQueryDate.mockImplementation(date => date.format('YYYY-MM-DD'));

        // Apply the mocks to the actual imported modules
        mockUseTopPostsStats.mockImplementation(mocks.mockUseTopPostsStats);
    });

    afterEach(function () {
        dateMocking.cleanup();
    });

    it('uses default range of 30 days when no range provided', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(), {wrapper});

        const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(30);

        expect(mockUseTopPostsStats).toHaveBeenCalledWith({
            searchParams: {
                date_from: expectedDateFrom,
                date_to: expectedDateTo,
                order: 'mrr desc'
            }
        });
    });

    it('uses default order of "mrr desc" when no order provided', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(7), {wrapper});

        const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(7);

        expect(mockUseTopPostsStats).toHaveBeenCalledWith({
            searchParams: {
                date_from: expectedDateFrom,
                date_to: expectedDateTo,
                order: 'mrr desc'
            }
        });
    });

    it('accepts custom range parameter', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(14), {wrapper});

        const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(14);

        expect(mockUseTopPostsStats).toHaveBeenCalledWith({
            searchParams: {
                date_from: expectedDateFrom,
                date_to: expectedDateTo,
                order: 'mrr desc'
            }
        });
    });

    it('accepts custom order parameter', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(30, 'free_members desc'), {wrapper});

        const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(30);

        expect(mockUseTopPostsStats).toHaveBeenCalledWith({
            searchParams: {
                date_from: expectedDateFrom,
                date_to: expectedDateTo,
                order: 'free_members desc'
            }
        });
    });

    it('accepts paid_members desc order', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(30, 'paid_members desc'), {wrapper});

        const {expectedDateFrom, expectedDateTo} = getExpectedDateRange(30);

        expect(mockUseTopPostsStats).toHaveBeenCalledWith({
            searchParams: {
                date_from: expectedDateFrom,
                date_to: expectedDateTo,
                order: 'paid_members desc'
            }
        });
    });

    it('filters out undefined values from search params', () => {
        const wrapper = TestWrapper;
        renderHook(() => useTopPostsStatsWithRange(7, 'mrr desc'), {wrapper});

        const calledWith = mockUseTopPostsStats.mock.calls[0]?.[0];

        expect(calledWith).toBeDefined();
        expect(calledWith?.searchParams).toBeDefined();

        // Ensure no undefined values are passed
        if (calledWith?.searchParams) {
            Object.values(calledWith.searchParams).forEach((value) => {
                expect(value).not.toBeUndefined();
            });
        }
    });

    it('returns the result from useTopPostsStats', () => {
        const wrapper = TestWrapper;
        const {result} = renderHook(() => useTopPostsStatsWithRange(), {wrapper});

        // Just verify that the hook returns something (the mocked result)
        expect(result.current).toBeDefined();
    });
});
