import { __, sprintf } from "@wordpress/i18n";
import { useEffect, useMemo, useRef, useState } from "@wordpress/element";
import { Button, Modal, RadioControl } from "@wordpress/components";

import PageSelectionTable from "./PageSelectionTable";
import SelectedPagesSummary from "./SelectedPagesSummary";
import { fuzzySearchPages } from "../utils/fuzzyPageSearch";
import {
    TARGET_MODE_ALL,
    TARGET_MODE_FULL_FLUSH,
    TARGET_MODE_SELECTED,
    normalizeTargetMode,
} from "../utils/targetMode";

function normalizePageId(value) {
    const parsed = Number.parseInt(value, 10);
    return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
}

function normalizePageIdList(values) {
    if (!Array.isArray(values)) {
        return [];
    }

    const seen = new Set();
    values.forEach((value) => {
        const normalized = normalizePageId(value);
        if (normalized !== null) {
            seen.add(normalized);
        }
    });

    return [...seen];
}

export default function PageTargetsSelector({
    idBase,
    availablePages,
    pageSelectionMeta = {},
    targetMode = "selected",
    selectedIds,
    onTargetModeChange,
    onSelectedIdsChange,
    hideTargetModeControl = false,
}) {
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [searchTerm, setSearchTerm] = useState("");
    const [draftSelectedIds, setDraftSelectedIds] = useState([]);
    const [lockedHeightPx, setLockedHeightPx] = useState(null);
    const modalContentRef = useRef(null);

    const normalizedSelectedIds = useMemo(
        () => normalizePageIdList(selectedIds),
        [selectedIds],
    );
    const mode = normalizeTargetMode(targetMode);
    const pageLimit = Number(pageSelectionMeta?.limit) || 0;
    const totalPages = Number(pageSelectionMeta?.total) || 0;
    const isTruncated = Boolean(pageSelectionMeta?.is_truncated);

    const openModal = () => {
        setDraftSelectedIds([...normalizedSelectedIds]);
        setSearchTerm("");
        setLockedHeightPx(null);
        setIsModalOpen(true);
    };

    const closeModal = () => {
        setLockedHeightPx(null);
        setIsModalOpen(false);
    };

    useEffect(() => {
        if (!isModalOpen) {
            return undefined;
        }

        const frameId = window.requestAnimationFrame(() => {
            const contentElement = modalContentRef.current;
            if (!contentElement) {
                return;
            }

            const measuredHeight = Math.round(
                contentElement.getBoundingClientRect().height,
            );
            if (measuredHeight > 0) {
                setLockedHeightPx(measuredHeight);
            }
        });

        const handleResize = () => {
            setLockedHeightPx(null);
        };

        window.addEventListener("resize", handleResize);

        return () => {
            window.cancelAnimationFrame(frameId);
            window.removeEventListener("resize", handleResize);
        };
    }, [isModalOpen]);

    const filteredPageRows = useMemo(
        () => fuzzySearchPages(availablePages, searchTerm),
        [availablePages, searchTerm],
    );

    const filteredPages = filteredPageRows.map(({ page }) => page);

    const highlightsByPageId = useMemo(() => {
        const map = new Map();
        filteredPageRows.forEach(({ page, highlights }) => {
            if (highlights) {
                const pageId = normalizePageId(page?.id);
                if (pageId !== null) {
                    map.set(pageId, highlights);
                }
            }
        });
        return map;
    }, [filteredPageRows]);

    const availablePageIdSet = useMemo(
        () =>
            new Set(
                (availablePages || [])
                    .map((page) => normalizePageId(page?.id))
                    .filter((pageId) => pageId !== null),
            ),
        [availablePages],
    );

    const visibleIds = filteredPages
        .map((page) => normalizePageId(page?.id))
        .filter((pageId) => pageId !== null);
    const visibleSelectedIds = visibleIds.filter((id) =>
        draftSelectedIds.includes(id),
    );
    const allSelected =
        visibleIds.length > 0 && visibleSelectedIds.length === visibleIds.length;
    const someSelected =
        visibleSelectedIds.length > 0 &&
        visibleSelectedIds.length < visibleIds.length;

    return (
        <div className='eci-page-targets'>
            {!hideTargetModeControl && (
                <RadioControl
                    label={__("Target mode", "cache-autopilot")}
                    selected={mode}
                    onChange={onTargetModeChange}
                    options={[
                        {
                            value: TARGET_MODE_ALL,
                            label: __("All pages", "cache-autopilot"),
                        },
                        {
                            value: TARGET_MODE_SELECTED,
                            label: __("Selected pages", "cache-autopilot"),
                        },
                        {
                            value: TARGET_MODE_FULL_FLUSH,
                            label: __("Purge all cache", "cache-autopilot"),
                        },
                    ]}
                />
            )}

            {mode === TARGET_MODE_ALL ? (
                <p className='ekesto-section-description is-italic is-small mt-md'>
                    {__("All published pages will be invalidated.", "cache-autopilot")}
                </p>
            ) : mode === TARGET_MODE_FULL_FLUSH ? (
                <p className='ekesto-section-description is-italic is-small mt-md'>
                    {__(
                        "Runs a full cache purge for this post type tab. Can be resource-intensive on large sites.",
                        "cache-autopilot",
                    )}
                </p>
            ) : (
                <>
                    {isTruncated && pageLimit > 0 && (
                        <p className='ekesto-section-description is-small is-italic mt-sm'>
                            {totalPages > 0
                                ? sprintf(
                                      __(
                                          "%1$d selectable pages available.",
                                          "cache-autopilot",
                                      ),
                                      totalPages,
                                  )
                                : sprintf(
                                      __(
                                          "Showing first %d selectable pages.",
                                          "cache-autopilot",
                                      ),
                                      pageLimit,
                                  )}
                        </p>
                    )}
                    <SelectedPagesSummary
                        selectedIds={normalizedSelectedIds}
                        availablePages={availablePages}
                        isTruncated={isTruncated}
                    />
                    <div className='mt-lg'>
                        <Button variant='secondary' onClick={openModal}>
                            {__("Select pages", "cache-autopilot")}
                        </Button>
                    </div>
                </>
            )}

            {isModalOpen && (
                <Modal
                    className='ekesto-settings-modal ekesto-settings-modal--wide ekesto-settings-modal--page-selector'
                    title={__("Select pages", "cache-autopilot")}
                    onRequestClose={closeModal}
                >
                    <div
                        ref={modalContentRef}
                        className={`ekesto-settings-modal__content${
                            lockedHeightPx !== null
                                ? " ekesto-settings-modal__content--height-locked"
                                : ""
                        }`}
                        style={
                            lockedHeightPx !== null
                                ? {
                                      "--eci-page-selector-modal-height": `${lockedHeightPx}px`,
                                  }
                                : undefined
                        }
                    >
                        <div className='ekesto-settings-modal__body'>
                            <div className='ekesto-search-container'>
                                <input
                                    type='text'
                                    className='ekesto-search-container__input'
                                    placeholder={__("Search pages", "cache-autopilot")}
                                    value={searchTerm}
                                    onChange={(event) =>
                                        setSearchTerm(event.target.value)
                                    }
                                />
                            </div>

                            <PageSelectionTable
                                pages={filteredPages}
                                selectedIds={draftSelectedIds}
                                allSelected={allSelected}
                                someSelected={someSelected}
                                highlightByPageId={highlightsByPageId}
                                onToggle={(pageId, isChecked) => {
                                    const normalizedPageId =
                                        normalizePageId(pageId);
                                    if (normalizedPageId === null) {
                                        return;
                                    }

                                    const nextIds = isChecked
                                        ? [
                                              ...draftSelectedIds,
                                              normalizedPageId,
                                          ]
                                        : draftSelectedIds.filter(
                                              (id) => id !== normalizedPageId,
                                          );
                                    setDraftSelectedIds(
                                        normalizePageIdList(nextIds),
                                    );
                                }}
                                onSelectAll={(isChecked) => {
                                    const nextIds = isChecked
                                        ? [
                                              ...new Set([
                                                  ...draftSelectedIds,
                                                  ...visibleIds,
                                              ]),
                                          ]
                                        : draftSelectedIds.filter(
                                              (id) => !visibleIds.includes(id),
                                          );
                                    setDraftSelectedIds(
                                        normalizePageIdList(nextIds),
                                    );
                                }}
                            />
                        </div>

                        <div className='ekesto-settings-modal__actions'>
                            <Button variant='secondary' onClick={closeModal}>
                                {__("Cancel", "cache-autopilot")}
                            </Button>
                            <Button
                                variant='primary'
                                onClick={() => {
                                    const normalizedDraftSelectedIds =
                                        normalizePageIdList(draftSelectedIds);
                                    const nextSelectedIds = isTruncated
                                        ? normalizedDraftSelectedIds
                                        : normalizedDraftSelectedIds.filter(
                                              (id) =>
                                                  availablePageIdSet.has(id),
                                          );

                                    onSelectedIdsChange(nextSelectedIds);
                                    closeModal();
                                }}
                            >
                                {__("Save", "cache-autopilot")}
                            </Button>
                        </div>
                    </div>
                </Modal>
            )}
        </div>
    );
}
