import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Box, Button, Menu, MenuItem, Typography } from "@mui/material";
import ListIcon from "@mui/icons-material/List";
import { skipToken, useQuery } from "@tanstack/react-query";
import hljs from "highlight.js/lib/core";
import plaintext from "highlight.js/lib/languages/plaintext";
import "highlight.js/styles/github.css";
import { Client } from "api/client/AhrimanClient";
import { QueryKeys } from "api/QueryKeys";
import { formatTimestamp } from "components/common/formatTimestamp";
import CopyButton from "components/common/CopyButton";
import type { LogRecord } from "api/types/LogRecord";
import type { RepositoryId } from "api/types/RepositoryId";

hljs.registerLanguage("plaintext", plaintext);

interface LogVersion {
    version: string;
    processId: string;
    created: number;
    logs: string;
}

interface BuildLogsTabProps {
    packageBase: string;
    repo: RepositoryId;
    refetchInterval: number | false;
}

function convertLogs(records: LogRecord[], filter?: (r: LogRecord) => boolean): string {
    return records
        .filter(filter || Boolean)
        .map((r) => `[${new Date(r.created * 1000).toISOString()}] ${r.message}`)
        .join("\n");
}

export default function BuildLogsTab({ packageBase, repo, refetchInterval }: BuildLogsTabProps): React.JSX.Element {
    const [activeIndex, setActiveIndex] = useState(0);
    const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
    const codeRef = useRef<HTMLElement>(null);
    const preRef = useRef<HTMLElement>(null);
    const initialScrollDone = useRef(false);
    const wasAtBottom = useRef(true);

    const handleScroll = useCallback(() => {
        if (preRef.current) {
            const el = preRef.current;
            wasAtBottom.current = el.scrollTop + el.clientHeight >= el.scrollHeight - 50;
        }
    }, []);

    const { data: allLogs } = useQuery<LogRecord[]>({
        queryKey: QueryKeys.logs(packageBase, repo),
        queryFn: () => Client.fetchLogs(packageBase, repo),
        enabled: !!packageBase,
    });

    // Build version selectors from all logs
    const versions = useMemo<LogVersion[]>(() => {
        if (!allLogs || allLogs.length === 0) {
            return [];
        }

        const grouped: Record<string, LogRecord & { minCreated: number }> = {};
        for (const record of allLogs) {
            const key = `${record.version}-${record.process_id}`;
            if (!grouped[key]) {
                grouped[key] = { ...record, minCreated: record.created };
            } else {
                grouped[key].minCreated = Math.min(grouped[key].minCreated, record.created);
            }
        }

        return Object.values(grouped)
            .sort((a, b) => b.minCreated - a.minCreated)
            .map((v) => ({
                version: v.version,
                processId: v.process_id,
                created: v.minCreated,
                logs: convertLogs(
                    allLogs,
                    (r) => r.version === v.version && r.process_id === v.process_id,
                ),
            }));
    }, [allLogs]);

    // Reset active index when logs data changes (React "adjusting state from props" pattern)
    const [prevAllLogs, setPrevAllLogs] = useState(allLogs);
    if (prevAllLogs !== allLogs) {
        setPrevAllLogs(allLogs);
        setActiveIndex(0);
    }

    // Reset scroll tracking when active version changes
    const activeVersionKey = versions[activeIndex] ? `${versions[activeIndex].version}-${versions[activeIndex].processId}` : null;
    useEffect(() => {
        initialScrollDone.current = false;
    }, [activeVersionKey]);

    // Refresh active version logs when using auto-refresh
    const activeVersion = versions[activeIndex];
    const { data: versionLogs } = useQuery<LogRecord[]>({
        queryKey: activeVersion
            ? QueryKeys.logsVersion(packageBase, repo, activeVersion.version, activeVersion.processId)
            : ["logs-none"],
        queryFn: activeVersion
            ? () => Client.fetchLogs(packageBase, repo, activeVersion.version, activeVersion.processId)
            : skipToken,
        enabled: !!activeVersion && !!refetchInterval,
        refetchInterval,
    });

    // Derive displayed logs: prefer fresh polled data when available
    const displayedLogs = useMemo(() => {
        if (versionLogs && versionLogs.length > 0) {
            return convertLogs(versionLogs);
        }
        return activeVersion?.logs ?? "";
    }, [versionLogs, activeVersion]);

    // Highlight code
    useEffect(() => {
        if (codeRef.current && displayedLogs) {
            codeRef.current.textContent = displayedLogs;
            delete codeRef.current.dataset.highlighted;
            hljs.highlightElement(codeRef.current);
        }
    }, [displayedLogs]);

    // Auto-scroll: always scroll to bottom on initial load, then only if already near bottom
    // and the user has no active text selection (to avoid disrupting copy workflows).
    // wasAtBottom is tracked via onScroll so it reflects position *before* new content arrives.
    useEffect(() => {
        if (preRef.current && displayedLogs) {
            const el = preRef.current;
            if (!initialScrollDone.current) {
                el.scrollTop = el.scrollHeight;
                initialScrollDone.current = true;
            } else {
                const hasSelection = !document.getSelection()?.isCollapsed;
                if (wasAtBottom.current && !hasSelection) {
                    el.scrollTop = el.scrollHeight;
                }
            }
        }
    }, [displayedLogs]);

    return (
        <Box sx={{ display: "flex", gap: 1, mt: 1 }}>
            <Box>
                <Button
                    size="small"
                    startIcon={<ListIcon />}
                    onClick={(e) => setAnchorEl(e.currentTarget)}
                />
                <Menu
                    anchorEl={anchorEl}
                    open={Boolean(anchorEl)}
                    onClose={() => setAnchorEl(null)}
                >
                    {versions.map((v, idx) => (
                        <MenuItem
                            key={`${v.version}-${v.processId}`}
                            selected={idx === activeIndex}
                            onClick={() => {
                                setActiveIndex(idx);
                                setAnchorEl(null);
                                initialScrollDone.current = false;
                            }}
                        >
                            <Typography variant="body2">{formatTimestamp(v.created)}</Typography>
                        </MenuItem>
                    ))}
                    {versions.length === 0 && (
                        <MenuItem disabled>No logs available</MenuItem>
                    )}
                </Menu>
            </Box>

            <Box sx={{ flex: 1, position: "relative" }}>
                <Box
                    ref={preRef}
                    component="pre"
                    onScroll={handleScroll}
                    sx={{
                        backgroundColor: "grey.100",
                        p: 2,
                        borderRadius: 1,
                        overflow: "auto",
                        height: 400,
                        fontSize: "0.8rem",
                        fontFamily: "monospace",
                        whiteSpace: "pre-wrap",
                        wordBreak: "break-all",
                    }}
                >
                    <code ref={codeRef} className="language-plaintext" />
                </Box>
                <Box sx={{ position: "absolute", top: 8, right: 8 }}>
                    <CopyButton getText={() => displayedLogs} />
                </Box>
            </Box>
        </Box>
    );
}
