import { useEffect, useRef, useState } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { Button, Notice } from "@wordpress/components";
import apiFetch from "@wordpress/api-fetch";
import { copySmall, copy, check, external } from "@wordpress/icons";
import {
    getBrotliProfileErrorMessage,
    getFallbackReasonDisplay,
    formatTransportUsedLabel,
} from "../utils/fallbackReason";

const COPY_ICON = copySmall || copy;

const parseIntOrZero = (value) => {
    const parsed = Number(value);
    if (!Number.isFinite(parsed) || parsed < 0) {
        return 0;
    }

    return Math.trunc(parsed);
};

const getEventRows = (log) => {
    const eventRows = Array.isArray(log?.event_rows) ? log.event_rows : [];

    return eventRows.filter((row) => {
        const url = typeof row?.url === "string" ? row.url.trim() : "";
        return url !== "";
    });
};

const getResultToneClass = (result) => {
    const normalized = typeof result === "string" ? result : "";

    if (normalized === "warmed") {
        return "is-warmed";
    }

    if (normalized === "failed") {
        return "is-failed";
    }

    if (normalized === "queued" || normalized.startsWith("queued_")) {
        return "is-queued";
    }

    return "is-other";
};

const formatResultLabel = (result) => {
    const normalized = typeof result === "string" ? result : "";

    if (normalized === "warmed") {
        return __("Warmed", "cache-autopilot");
    }

    if (normalized === "failed") {
        return __("Failed", "cache-autopilot");
    }

    if (normalized === "queued" || normalized.startsWith("queued_")) {
        return __("Queued", "cache-autopilot");
    }

    if (normalized === "skipped_membership_miss") {
        return __("Skipped", "cache-autopilot");
    }

    if (normalized === "unknown" || normalized === "") {
        return __("Unknown", "cache-autopilot");
    }

    return normalized.replace(/_/g, " ");
};

const formatEventErrorHint = (errorCode) => {
    const normalized = typeof errorCode === "string" ? errorCode.trim() : "";

    if (normalized === "stale_sitemap_membership") {
        return __(
            "This URL is no longer present in the current sitemap membership cache, so warmup skipped it.",
            "cache-autopilot",
        );
    }

    return normalized;
};

const formatStatusCode = (statusCode) => {
    const code = parseIntOrZero(statusCode);
    return code > 0 ? String(code) : "—";
};

const formatDurationMs = (durationMs) => {
    const ms = parseIntOrZero(durationMs);
    return ms > 0 ? String(ms) : "—";
};

const hasText = (value) => typeof value === "string" && value.trim() !== "";

const getFailedRowDiagnostics = (eventRow) => {
    if (eventRow?.result !== "failed") {
        return [];
    }

    const rows = [];
    const fallbackReasonCode = hasText(eventRow?.fallback_reason)
        ? eventRow.fallback_reason.trim()
        : "";
    const fallbackUsed = eventRow?.fallback_used === true;
    const transportUsed = hasText(eventRow?.transport_used)
        ? eventRow.transport_used.trim()
        : "";
    const brotliAttempted = eventRow?.brotli_attempted === true;
    const brotliCode = parseIntOrZero(eventRow?.brotli_code);
    const finalStatusCode = parseIntOrZero(eventRow?.status_code);
    const brotliErrorCode = hasText(eventRow?.brotli_error)
        ? eventRow.brotli_error.trim()
        : "";
    const brotliSkipReason = hasText(eventRow?.brotli_skip_reason)
        ? eventRow.brotli_skip_reason.trim()
        : "";

    if (fallbackReasonCode !== "") {
        const fallbackReason = getFallbackReasonDisplay(fallbackReasonCode).text;
        rows.push(
            sprintf(
                /* translators: %s: Human-readable fallback reason. */
                __("Fallback triggered: %s", "cache-autopilot"),
                fallbackReason || fallbackReasonCode,
            ),
        );
    } else if (fallbackUsed) {
        rows.push(
            __("Fallback triggered, but no reason was recorded.", "cache-autopilot"),
        );
    }

    if (transportUsed !== "") {
        rows.push(
            sprintf(
                /* translators: %s: Warmup transport label. */
                __("Final request: %s", "cache-autopilot"),
                formatTransportUsedLabel(transportUsed),
            ),
        );
    }

    if (brotliCode > 0) {
        rows.push(
            sprintf(
                /* translators: %d: HTTP response status. */
                __("Browser-profile status: HTTP %d", "cache-autopilot"),
                brotliCode,
            ),
        );
    } else if (brotliAttempted && brotliErrorCode !== "") {
        rows.push(
            sprintf(
                /* translators: %s: Human-readable browser-profile request error. */
                __("Browser-profile result: %s", "cache-autopilot"),
                getBrotliProfileErrorMessage(brotliErrorCode),
            ),
        );
    } else if (brotliSkipReason !== "") {
        rows.push(
            sprintf(
                /* translators: %s: Reason the browser-profile request was skipped. */
                __("Browser-profile attempt: skipped (%s).", "cache-autopilot"),
                getFallbackReasonDisplay(brotliSkipReason).text || brotliSkipReason,
            ),
        );
    }

    if (finalStatusCode > 0) {
        rows.push(
            sprintf(
                /* translators: %d: Final HTTP response status. */
                __("Final result: HTTP %d", "cache-autopilot"),
                finalStatusCode,
            ),
        );
    }

    return rows;
};

const copyTextToClipboard = async (text) => {
    if (typeof text !== "string" || text === "") {
        return false;
    }

    if (
        typeof navigator !== "undefined"
        && navigator.clipboard
        && typeof navigator.clipboard.writeText === "function"
    ) {
        await navigator.clipboard.writeText(text);
        return true;
    }

    if (typeof document === "undefined") {
        return false;
    }

    const helper = document.createElement("textarea");
    helper.value = text;
    helper.setAttribute("readonly", "readonly");
    helper.style.position = "fixed";
    helper.style.opacity = "0";
    helper.style.pointerEvents = "none";
    document.body.appendChild(helper);
    helper.select();

    let copied = false;
    try {
        copied = document.execCommand("copy");
    } finally {
        document.body.removeChild(helper);
    }

    return copied;
};

export default function RecentLogDetails({ log, detailsId }) {
    const logKey = log?.id ?? "log";
    const [copyLockMap, setCopyLockMap] = useState({});
    const copyTimersRef = useRef({});
    const [loadedLogDetails, setLoadedLogDetails] = useState(null);
    const [loadingAllRows, setLoadingAllRows] = useState(false);
    const [loadAllError, setLoadAllError] = useState("");

    const activeLog = loadedLogDetails || log;
    const eventRows = getEventRows(activeLog);
    const detailsAvailable = Boolean(activeLog?.event_details_available) || eventRows.length > 0;
    const eventRowsTotal = parseIntOrZero(activeLog?.event_rows_total) || eventRows.length;
    const eventRowsShown = parseIntOrZero(activeLog?.event_rows_shown) || eventRows.length;
    const eventRowsOverflow = parseIntOrZero(activeLog?.event_rows_overflow);
    const warmedUrls = parseIntOrZero(activeLog?.warmed_urls);
    const isRunning = activeLog?.status === "running";
    const isPreparing = activeLog?.status === "preparing";
    const hasVisibleWarmedRows = eventRows.some((eventRow) => eventRow?.result === "warmed");
    const showRunningSummary = isRunning && warmedUrls > 0 && !hasVisibleWarmedRows;

    useEffect(() => {
        return () => {
            Object.values(copyTimersRef.current).forEach((timerId) => {
                clearTimeout(timerId);
            });
            copyTimersRef.current = {};
        };
    }, []);

    useEffect(() => {
        setLoadedLogDetails(null);
        setLoadAllError("");
        setLoadingAllRows(false);
    }, [log?.id, log?.event_rows_total, log?.event_rows_shown, log?.status]);

    const releaseCopyLock = (rowKey) => {
        setCopyLockMap((current) => {
            if (!current[rowKey]) {
                return current;
            }

            const next = { ...current };
            delete next[rowKey];
            return next;
        });

        if (copyTimersRef.current[rowKey]) {
            clearTimeout(copyTimersRef.current[rowKey]);
            delete copyTimersRef.current[rowKey];
        }
    };

    const scheduleCopyLockRelease = (rowKey) => {
        if (copyTimersRef.current[rowKey]) {
            clearTimeout(copyTimersRef.current[rowKey]);
        }

        copyTimersRef.current[rowKey] = setTimeout(() => {
            releaseCopyLock(rowKey);
        }, 2000);
    };

    const handleCopyUrl = async (rowKey, url) => {
        if (copyLockMap[rowKey] || copyTimersRef.current[rowKey]) {
            return;
        }

        setCopyLockMap((current) => ({
            ...current,
            [rowKey]: true,
        }));
        scheduleCopyLockRelease(rowKey);

        try {
            await copyTextToClipboard(url);
        } catch {
            releaseCopyLock(rowKey);
        }
    };

    const handleOpenUrl = (url) => {
        if (typeof window === "undefined" || typeof url !== "string" || url === "") {
            return;
        }

        window.open(url, "_blank", "noopener,noreferrer");
    };

    const handleLoadAllRows = async () => {
        const logId = parseIntOrZero(log?.id);
        if (loadingAllRows || logId < 1 || eventRowsOverflow < 1) {
            return;
        }

        setLoadingAllRows(true);
        setLoadAllError("");

        try {
            const response = await apiFetch({
                path: `/ekesto-cache-warmup/v1/logs/${logId}/details?all=1`,
            });
            const detailsLog = response?.log;
            if (!detailsLog || typeof detailsLog !== "object") {
                throw new Error(__("Failed to load all entries.", "cache-autopilot"));
            }

            setLoadedLogDetails(detailsLog);
        } catch (error) {
            setLoadAllError(error?.message || __("Failed to load all entries.", "cache-autopilot"));
        } finally {
            setLoadingAllRows(false);
        }
    };

    return (
        <div id={detailsId} className='ecw-log-table__details-panel'>
            {detailsAvailable && eventRows.length > 0 ? (
                <>
                    <table className='ecw-log-table__details-table'>
                        <thead>
                            <tr>
                                <th>{__("Result", "cache-autopilot")}</th>
                                <th>{__("URL", "cache-autopilot")}</th>
                                <th>{__("HTTP", "cache-autopilot")}</th>
                                <th>{__("ms", "cache-autopilot")}</th>
                                <th> </th>
                            </tr>
                        </thead>
                        <tbody>
                            {eventRows.map((eventRow, eventIndex) => {
                                const rowKey = `${logKey}-${eventIndex}-${eventRow.url}`;
                                const isCopyLocked = Boolean(
                                    copyLockMap[rowKey],
                                );
                                const failedRowDiagnostics = getFailedRowDiagnostics(eventRow);
                                const copyLabel = isCopyLocked
                                    ? __("Copied", "cache-autopilot")
                                    : __("Copy URL", "cache-autopilot");

                                return (
                                    <tr key={rowKey}>
                                        <td>
                                            <span
                                                className={`ecw-log-table__result-pill ${getResultToneClass(
                                                    eventRow.result,
                                                )}`}
                                            >
                                                {formatResultLabel(
                                                    eventRow.result,
                                                )}
                                            </span>
                                        </td>
                                        <td className='ecw-log-table__url-cell'>
                                            {eventRow.url}
                                            {formatEventErrorHint(eventRow.error) ? (
                                                <div className='description'>
                                                    {formatEventErrorHint(eventRow.error)}
                                                </div>
                                            ) : null}
                                            {failedRowDiagnostics.map(
                                                (line, lineIndex) => (
                                                    <div
                                                        key={`${rowKey}-diag-${lineIndex}`}
                                                        className='description'
                                                    >
                                                        {line}
                                                    </div>
                                                ),
                                            )}
                                        </td>
                                        <td>
                                            {formatStatusCode(
                                                eventRow.status_code,
                                            )}
                                        </td>
                                        <td>
                                            {formatDurationMs(
                                                eventRow.duration_ms,
                                            )}
                                        </td>
                                        <td className='ecw-log-table__icon-actions'>
                                            <Button
                                                icon={
                                                    isCopyLocked
                                                        ? check
                                                        : COPY_ICON
                                                }
                                                className='ecw-log-table__icon-button'
                                                onClick={() =>
                                                    handleCopyUrl(
                                                        rowKey,
                                                        eventRow.url,
                                                    )
                                                }
                                                aria-label={copyLabel}
                                                label={copyLabel}
                                                disabled={isCopyLocked}
                                            />
                                            <Button
                                                icon={external}
                                                className='ecw-log-table__icon-button'
                                                onClick={() =>
                                                    handleOpenUrl(eventRow.url)
                                                }
                                                aria-label={__("Open URL", "cache-autopilot")}
                                                label={__("Open URL", "cache-autopilot")}
                                            />
                                        </td>
                                    </tr>
                                );
                            })}
                        </tbody>
                    </table>
                    {showRunningSummary ? (
                        <p className='ecw-log-table__details-overflow'>
                            {sprintf(
                                /* translators: %d: Number of URLs warmed so far. */
                                __(
                                    "%d URLs warmed so far. Full URL list appears when this run finishes.",
                                    "cache-autopilot",
                                ),
                                warmedUrls,
                            )}
                        </p>
                    ) : null}
                    {isPreparing ? (
                        <p className='ecw-log-table__details-overflow'>
                            {__(
                                "Preparing the full warmup plan. Buffered targeted URLs appear here before the sitemap queue is materialized.",
                                "cache-autopilot",
                            )}
                        </p>
                    ) : null}
                    {eventRowsTotal > 0 ? (
                        <p className='ecw-log-table__details-overflow'>
                            {sprintf(
                                /* translators: 1: Displayed URL count, 2: Total URL count. */
                                __("Showing %1$d of %2$d URLs.", "cache-autopilot"),
                                eventRowsShown,
                                eventRowsTotal,
                            )}
                        </p>
                    ) : null}
                    {eventRowsOverflow > 0 ? (
                        <div className='ecw-log-table__details-load-actions'>
                            <Button
                                variant='secondary'
                                onClick={handleLoadAllRows}
                                isBusy={loadingAllRows}
                                disabled={loadingAllRows}
                            >
                                {sprintf(
                                    /* translators: %d: Number of remaining URLs. */
                                    __("Load remaining %d URLs", "cache-autopilot"),
                                    eventRowsOverflow,
                                )}
                            </Button>
                            {loadAllError ? (
                                <Notice
                                    status='error'
                                    isDismissible={false}
                                >
                                    {loadAllError}
                                </Notice>
                            ) : null}
                        </div>
                    ) : null}
                </>
            ) : (
                <p className='ecw-log-table__details-empty'>
                    {isPreparing
                        ? __(
                            "Preparing the full warmup plan. URL details will appear after the queue is materialized.",
                            "cache-autopilot",
                        )
                        : __("No URL details available for this run.", "cache-autopilot")}
                </p>
            )}
        </div>
    );
}
