import MainLayout from '@components/layout/main-layout';
import MembersActions from './components/members-actions';
import MembersEmptyState from './components/members-empty-state';
import MembersFilters from './components/members-filters';
import MembersHeaderSearch from './components/members-header-search';
import MembersHelpCards from './components/members-help-cards';
import MembersList from './components/members-list';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {Button, EmptyIndicator, LoadingIndicator} from '@tryghost/shade/components';
import {FilterBar, PageHeader} from '@tryghost/shade/patterns';
import {ListPage} from '@tryghost/shade/page-templates';
import {LucideIcon, cn, formatNumber} from '@tryghost/shade/utils';
import {buildMemberListSearchParams, getMemberActiveColumns} from './member-query-params';
import {canBulkDeleteMembers, shouldShowMembersLoading} from './members-view-state';
import {getSettingValue, useBrowseSettings} from '@tryghost/admin-x-framework/api/settings';
import {getSiteTimezone} from '@src/utils/get-site-timezone';
import {shouldDelayMembersDateFilterHydration, useMembersFilterState} from './hooks/use-members-filter-state';
import {useActiveMemberView, useMemberViews} from './hooks/use-member-views';
import {useBrowseConfig} from '@tryghost/admin-x-framework/api/config';
import {useBrowseMembersInfinite} from '@tryghost/admin-x-framework/api/members';
import {useDebounce} from 'use-debounce';
import {useLocation, useSearchParams} from 'react-router';

const SEARCH_DEBOUNCE_MS = 250;
const MEMBERS_HELP_CARDS_LIMIT = 6;

const MembersPage: React.FC<{timezone: string; membershipsEnabled: boolean}> = ({timezone, membershipsEnabled}) => {
    const headerRef = useRef<HTMLDivElement | null>(null);
    const setHeaderContentRef = useCallback((node: HTMLDivElement | null) => {
        headerRef.current = node?.closest('[data-list-page="header"]') as HTMLDivElement | null;
    }, []);
    const {filters, nql, search, setFilters, setSearch, hasFilterOrSearch, clearAll} = useMembersFilterState(timezone);
    const location = useLocation();
    const {data: configData} = useBrowseConfig();
    const savedViews = useMemberViews();
    const activeView = useActiveMemberView(savedViews, nql);
    const [showMobileSearch, setShowMobileSearch] = useState(false);
    const [mobileSearchOpenedByUser, setMobileSearchOpenedByUser] = useState(false);
    const [searchInput, setSearchInput] = useState(search);
    const [debouncedSearch] = useDebounce(searchInput, SEARCH_DEBOUNCE_MS);

    const emailAnalyticsEnabled = configData?.config?.emailAnalytics === true;

    const activeColumns = useMemo(() => {
        return getMemberActiveColumns(filters);
    }, [filters]);

    const canBulkDelete = useMemo(() => {
        return canBulkDeleteMembers(filters, nql);
    }, [filters, nql]);

    const searchParams = useMemo(() => {
        return buildMemberListSearchParams({
            filters,
            nql,
            search
        });
    }, [filters, nql, search]);

    const {
        data,
        isError,
        isFetching,
        isFetchingNextPage,
        refetch,
        fetchNextPage,
        hasNextPage
    } = useBrowseMembersInfinite({
        searchParams,
        keepPreviousData: true
    });

    const shouldShowLoading = shouldShowMembersLoading({
        isFetching,
        isFetchingNextPage
    });

    const totalMembers = data?.meta?.pagination?.total ?? 0;
    const hasFilters = filters.length > 0;
    const shouldShowMobileSearchRow = showMobileSearch;
    const shouldShowFiltersRow = hasFilters;
    const shouldShowMembersHelpCards = !hasFilterOrSearch && !shouldShowLoading && !isError && totalMembers < MEMBERS_HELP_CARDS_LIMIT;

    useEffect(() => {
        setSearchInput(search);
    }, [search]);

    useEffect(() => {
        if (debouncedSearch !== search) {
            setSearch(debouncedSearch);
        }
    }, [debouncedSearch, search, setSearch]);

    const handleMobileSearchToggle = () => {
        if (showMobileSearch) {
            setShowMobileSearch(false);
            setMobileSearchOpenedByUser(false);
            return;
        }

        setMobileSearchOpenedByUser(true);
        setShowMobileSearch(true);
    };

    const filtersClassName = 'flex-col gap-4 lg:flex-row lg:items-center sidebar:gap-6 lg:gap-6';

    return (
        <MainLayout>
            <ListPage data-testid="members-page">
                <ListPage.Header className="py-4 sidebar:py-6">
                    <div ref={setHeaderContentRef} className="flex flex-col gap-4 sidebar:gap-6">
                        <PageHeader
                            blurredBackground={false}
                            sticky={false}
                        >
                            <PageHeader.Left>
                                <PageHeader.Title>
                                    Members{' '}
                                    {!shouldShowLoading && (
                                        <PageHeader.Count className="hidden sm:inline">
                                            {formatNumber(totalMembers)}
                                        </PageHeader.Count>
                                    )}
                                </PageHeader.Title>
                            </PageHeader.Left>
                            <PageHeader.Actions>
                                <PageHeader.ActionGroup className="ml-auto flex-wrap justify-end sm:ml-0 sm:flex-nowrap">
                                    <div className="hidden lg:flex">
                                        <MembersHeaderSearch
                                            search={searchInput}
                                            onSearchChange={setSearchInput}
                                        />
                                    </div>
                                    <Button
                                        aria-label={showMobileSearch ? 'Hide member search' : 'Show member search'}
                                        className={cn('lg:hidden', showMobileSearch && 'bg-secondary hover:bg-secondary')}
                                        variant="outline"
                                        onClick={handleMobileSearchToggle}
                                    >
                                        <LucideIcon.Search className="size-4" />
                                    </Button>
                                    {!hasFilters && (
                                        <MembersFilters
                                            activeView={activeView}
                                            filters={filters}
                                            iconOnly={true}
                                            nql={nql}
                                            savedViews={savedViews}
                                            onFiltersChange={setFilters}
                                        />
                                    )}
                                    <MembersActions
                                        canBulkDelete={canBulkDelete}
                                        hasFilterOrSearch={hasFilterOrSearch}
                                        memberCount={totalMembers}
                                        nql={nql}
                                        search={search}
                                        onImportComplete={() => {
                                            void refetch();
                                        }}
                                    />
                                </PageHeader.ActionGroup>
                            </PageHeader.Actions>
                        </PageHeader>

                        {(shouldShowFiltersRow || shouldShowMobileSearchRow) && (
                            <FilterBar className={cn(filtersClassName, !shouldShowFiltersRow && 'lg:hidden')}>
                                {shouldShowMobileSearchRow && (
                                    <div className="w-full lg:hidden">
                                        <MembersHeaderSearch
                                            ariaLabel="Search members mobile"
                                            autoFocus={mobileSearchOpenedByUser}
                                            search={searchInput}
                                            onSearchChange={setSearchInput}
                                        />
                                    </div>
                                )}
                                {shouldShowFiltersRow && (
                                    <MembersFilters
                                        activeView={activeView}
                                        filters={filters}
                                        nql={nql}
                                        savedViews={savedViews}
                                        onFiltersChange={setFilters}
                                    />
                                )}
                            </FilterBar>
                        )}
                    </div>
                </ListPage.Header>
                <ListPage.Body>
                    {shouldShowLoading ? (
                        <div className="flex flex-1 items-center justify-center">
                            <LoadingIndicator size="lg" />
                        </div>
                    ) : isError ? (
                        <div className="mb-16 flex flex-1 flex-col items-center justify-center">
                            <h2 className="mb-2 text-xl font-medium">
                                Error loading members
                            </h2>
                            <p className="mb-4 text-muted-foreground">
                                Please reload the page to try again
                            </p>
                            <Button onClick={() => window.location.reload()}>
                                Reload page
                            </Button>
                        </div>
                    ) : !data?.members.length ? (
                        hasFilterOrSearch ? (
                            <div className="flex flex-1 flex-col items-center justify-center">
                                <EmptyIndicator
                                    actions={
                                        <Button
                                            variant="outline"
                                            onClick={() => clearAll({replace: false})}
                                        >
                                            Show all members
                                        </Button>
                                    }
                                    title="No matching members found."
                                >
                                    <LucideIcon.Users />
                                </EmptyIndicator>
                            </div>
                        ) : (
                            <MembersEmptyState membershipsEnabled={membershipsEnabled} onMemberCreated={async () => {
                                await refetch();
                            }} />
                        )
                    ) : (
                        <MembersList
                            activeColumns={activeColumns}
                            backPath={`${location.pathname}${location.search}`}
                            fetchNextPage={fetchNextPage}
                            hasNextPage={hasNextPage}
                            isFetchingNextPage={isFetchingNextPage}
                            isLoading={isFetching && !isFetchingNextPage}
                            items={data.members}
                            pageHeaderRef={headerRef}
                            showEmailOpenRate={emailAnalyticsEnabled}
                            timezone={timezone}
                            totalItems={totalMembers}
                        />
                    )}
                    {shouldShowMembersHelpCards && <MembersHelpCards />}
                </ListPage.Body>
            </ListPage>
        </MainLayout>
    );
};

const Members: React.FC = () => {
    const [searchParams] = useSearchParams();
    const {data: settingsData, isLoading: isSettingsLoading} = useBrowseSettings({});
    const filterParam = searchParams.get('filter') ?? undefined;
    const hasResolvedSettings = Boolean(settingsData?.settings);
    const shouldDelayHydration = shouldDelayMembersDateFilterHydration(filterParam, hasResolvedSettings, isSettingsLoading);

    if (isSettingsLoading || !settingsData?.settings || shouldDelayHydration) {
        return (
            <MainLayout>
                <ListPage>
                    <ListPage.Header className="py-4 sidebar:py-6">
                        <PageHeader
                            blurredBackground={false}
                            sticky={false}
                        >
                            <PageHeader.Left>
                                <PageHeader.Title>Members</PageHeader.Title>
                            </PageHeader.Left>
                        </PageHeader>
                    </ListPage.Header>
                    <ListPage.Body>
                        <div className="flex flex-1 items-center justify-center">
                            <LoadingIndicator size="lg" />
                        </div>
                    </ListPage.Body>
                </ListPage>
            </MainLayout>
        );
    }

    const timezone = getSiteTimezone(settingsData.settings);
    const membersSignupAccess = getSettingValue<string>(settingsData.settings, 'members_signup_access');
    const membershipsEnabled = membersSignupAccess !== 'none';

    return <MembersPage membershipsEnabled={membershipsEnabled} timezone={timezone} />;
};

export default Members;
