"use client";

import { useQuery, type UseQueryOptions } from "@tanstack/react-query";
import type { ColumnFiltersState, OnChangeFn, PaginationState, SortingState } from "@tanstack/react-table";
import moment from "moment";
import { useCallback, useEffect, useMemo, useState } from "react";

import { AutoRouterModelGroupsProvider } from "@/components/shared/table_cells";
import type { KeyResponse } from "../key_team_helpers/key_list";
import { keyInfoV1Call, uiSpendLogsCall } from "../networking";
import KeyInfoView from "../templates/key_info_view";
import type { LogEntry } from "./columns";
import { AGENT_CALL_TYPES, MCP_CALL_TYPES } from "./constants";
import {
  DEFAULT_LOGS_SORTING,
  formatLogsWindow,
  getLogsWindowEndBound,
  LOG_FILTER_IDS,
  type PaginatedResponse,
  useLogFilterLogic,
} from "./log_filter_logic";
import { useLogDetailRouting } from "./logDetailRouting";
import { LogDetailsDrawer } from "./LogDetailsDrawer";
import { LiveTailBanner, LogsTableToolbar } from "./LogsTableToolbar";
import { RequestLogsTable } from "./RequestLogsTable";

const PAGE_SIZE = 50;
const DEFAULT_INTERVAL = { value: 24, unit: "hours" };

interface RequestLogsPanelProps {
  accessToken: string;
  token: string;
  userRole: string;
  userID: string;
  isActive: boolean;
}

interface SessionComposition {
  llm: number;
  agent: number;
  mcp: number;
}

export default function RequestLogsPanel({ accessToken, token, userRole, userID, isActive }: RequestLogsPanelProps) {
  const [pagination, setPagination] = useState<PaginationState>({ pageIndex: 0, pageSize: PAGE_SIZE });
  const [sorting, setSorting] = useState<SortingState>(DEFAULT_LOGS_SORTING);
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);

  const [startTime, setStartTime] = useState<string>(moment().subtract(24, "hours").format("YYYY-MM-DDTHH:mm"));
  const [endTime, setEndTime] = useState<string>(moment().format("YYYY-MM-DDTHH:mm"));
  const [isCustomDate, setIsCustomDate] = useState(false);
  const [selectedTimeInterval, setSelectedTimeInterval] = useState<{ value: number; unit: string }>(DEFAULT_INTERVAL);

  const [selectedKeyIdInfoView, setSelectedKeyIdInfoView] = useState<string | null>(null);
  const [selectedLog, setSelectedLog] = useState<LogEntry | null>(null);

  const {
    logId: urlLogId,
    sessionId: urlSessionId,
    openLog,
    openSession,
    selectLog,
    close: closeUrlLog,
  } = useLogDetailRouting();

  const [isLiveTail, setIsLiveTail] = useState<boolean>(() => {
    const storedValue = sessionStorage.getItem("isLiveTail");
    return storedValue !== null ? JSON.parse(storedValue) : true;
  });

  useEffect(() => {
    sessionStorage.setItem("isLiveTail", JSON.stringify(isLiveTail));
  }, [isLiveTail]);

  const [excludeInternalHealthChecks, setExcludeInternalHealthChecks] = useState<boolean>(
    () => sessionStorage.getItem("excludeInternalHealthChecks") === "true",
  );

  useEffect(() => {
    sessionStorage.setItem("excludeInternalHealthChecks", JSON.stringify(excludeInternalHealthChecks));
  }, [excludeInternalHealthChecks]);

  const { logsQuery, filteredLogs, allTeams } = useLogFilterLogic({
    accessToken,
    token,
    userRole,
    userID,
    columnFilters,
    activeTab: isActive ? "request logs" : "inactive",
    isLiveTail,
    excludeInternalHealthChecks,
    startTime,
    endTime,
    pagination,
    isCustomDate,
    sorting,
  });

  // Follow the table's own last fetch so a live-tail refresh carries the filter
  // window with it; before the first fetch, fall back to the stored end time.
  const windowEndBound = getLogsWindowEndBound(logsQuery.dataUpdatedAt || Date.parse(endTime));
  const logsWindow = useMemo(
    () => formatLogsWindow(startTime, endTime, isCustomDate, windowEndBound),
    [startTime, endTime, isCustomDate, windowEndBound],
  );

  const keyInfoQueryOptions: UseQueryOptions<KeyResponse | null> = {
    queryKey: ["requestLogsKeyInfo", selectedKeyIdInfoView, accessToken],
    queryFn: async () => {
      if (selectedKeyIdInfoView === null) return null;
      const keyData = await keyInfoV1Call(accessToken, selectedKeyIdInfoView);
      return {
        ...keyData["info"],
        token: selectedKeyIdInfoView,
        api_key: selectedKeyIdInfoView,
      };
    },
    enabled: selectedKeyIdInfoView !== null,
  };

  const { data: selectedKeyInfo } = useQuery(keyInfoQueryOptions);

  const urlLogQueryOptions: UseQueryOptions<LogEntry | null> = {
    queryKey: ["logs", "byId", urlLogId, accessToken],
    queryFn: async () => {
      if (urlLogId === null) return null;
      const window = formatLogsWindow(startTime, endTime, isCustomDate);
      const response: PaginatedResponse = await uiSpendLogsCall({
        accessToken,
        start_date: window.start_date,
        end_date: window.end_date,
        page: 1,
        page_size: 1,
        params: { request_id: urlLogId },
      });
      return response.data.find((log) => log.request_id === urlLogId) ?? null;
    },
    enabled: urlLogId !== null && selectedLog?.request_id !== urlLogId,
    staleTime: Infinity,
  };

  const { data: urlLog } = useQuery(urlLogQueryOptions);

  const displayLog = useMemo<LogEntry | null>(() => {
    if (urlLogId === null) return null;
    if (selectedLog?.request_id === urlLogId) return selectedLog;
    return filteredLogs.data.find((log) => log.request_id === urlLogId) ?? urlLog ?? null;
  }, [urlLogId, selectedLog, filteredLogs.data, urlLog]);

  const displaySessionId = useMemo<string | null>(() => {
    if (urlSessionId !== null) return urlSessionId;
    if (displayLog?.session_id !== undefined && (displayLog.session_total_count || 1) > 1) {
      return displayLog.session_id;
    }
    return null;
  }, [urlSessionId, displayLog]);

  const isDrawerOpen = displayLog !== null || displaySessionId !== null;

  const rows = useMemo<LogEntry[]>(() => {
    const searchedLogs = filteredLogs.data;

    const sessionCompositionById = searchedLogs.reduce<Record<string, SessionComposition>>((acc, log) => {
      if (!log.session_id) return acc;
      if (!acc[log.session_id]) {
        acc[log.session_id] = { llm: 0, agent: 0, mcp: 0 };
      }
      if (MCP_CALL_TYPES.includes(log.call_type)) {
        acc[log.session_id].mcp += 1;
      } else if (AGENT_CALL_TYPES.includes(log.call_type)) {
        acc[log.session_id].agent += 1;
      } else {
        acc[log.session_id].llm += 1;
      }
      return acc;
    }, {});

    const sessionRepresentativeMap = new Map<string, { requestId: string; isMcp: boolean }>();
    for (const log of searchedLogs) {
      if (!log.session_id || (log.session_total_count || 1) <= 1) continue;
      const isMcp = MCP_CALL_TYPES.includes(log.call_type);
      const existing = sessionRepresentativeMap.get(log.session_id);
      if (!existing || (existing.isMcp && !isMcp)) {
        sessionRepresentativeMap.set(log.session_id, { requestId: log.request_id, isMcp });
      }
    }

    return searchedLogs
      .map((log) => {
        const sessionComposition = log.session_id ? sessionCompositionById[log.session_id] : undefined;
        return {
          ...log,
          session_llm_count: sessionComposition?.llm ?? undefined,
          session_mcp_count: sessionComposition?.mcp ?? undefined,
          session_agent_count: sessionComposition?.agent ?? undefined,
        };
      })
      .filter((log) => {
        if (!log.session_id || (log.session_total_count || 1) <= 1) return true;
        return sessionRepresentativeMap.get(log.session_id)?.requestId === log.request_id;
      });
  }, [filteredLogs.data]);

  const searchTerm = useMemo(() => {
    const entry = columnFilters.find((filter) => filter.id === LOG_FILTER_IDS.REQUEST_ID);
    return typeof entry?.value === "string" ? entry.value : "";
  }, [columnFilters]);

  const handleSearchChange = useCallback((value: string) => {
    setColumnFilters((previous) => {
      const others = previous.filter((filter) => filter.id !== LOG_FILTER_IDS.REQUEST_ID);
      return value === "" ? others : [...others, { id: LOG_FILTER_IDS.REQUEST_ID, value }];
    });
    setPagination((previous) => ({ ...previous, pageIndex: 0 }));
  }, []);

  const handleSortingChange = useCallback<OnChangeFn<SortingState>>((updaterOrValue) => {
    setSorting(updaterOrValue);
    setPagination((previous) => ({ ...previous, pageIndex: 0 }));
  }, []);

  const handleColumnFiltersChange = useCallback<OnChangeFn<ColumnFiltersState>>((updaterOrValue) => {
    setColumnFilters(updaterOrValue);
    setPagination((previous) => ({ ...previous, pageIndex: 0 }));
  }, []);

  const resetToFirstPage = useCallback(() => {
    setPagination((previous) => ({ ...previous, pageIndex: 0 }));
  }, []);

  const handleExcludeInternalHealthChecksChange = useCallback(
    (value: boolean) => {
      setExcludeInternalHealthChecks(value);
      resetToFirstPage();
    },
    [resetToFirstPage],
  );

  const handleResetFilters = useCallback(() => {
    setColumnFilters([]);
    setStartTime(moment().subtract(24, "hours").format("YYYY-MM-DDTHH:mm"));
    setEndTime(moment().format("YYYY-MM-DDTHH:mm"));
    setIsCustomDate(false);
    setSelectedTimeInterval(DEFAULT_INTERVAL);
    resetToFirstPage();
  }, [resetToFirstPage]);

  const handleRowClick = useCallback(
    (log: LogEntry) => {
      setSelectedLog(log);
      if (log.session_id && (log.session_total_count || 1) > 1) {
        openSession(log.session_id, log.request_id);
      } else {
        openLog(log.request_id);
      }
    },
    [openLog, openSession],
  );

  const handleSessionClick = useCallback(
    (sessionId: string) => {
      if (!sessionId) return;
      const log = rows.find((candidate) => candidate.session_id === sessionId) ?? null;
      setSelectedLog(log);
      openSession(sessionId, log?.request_id ?? null);
    },
    [rows, openSession],
  );

  const handleSelectLog = useCallback(
    (log: LogEntry) => {
      setSelectedLog(log);
      selectLog(log.request_id, displaySessionId);
    },
    [selectLog, displaySessionId],
  );

  const handleKeyHashClick = useCallback((keyHash: string) => {
    setSelectedKeyIdInfoView(keyHash);
  }, []);

  if (selectedKeyInfo && selectedKeyIdInfoView && selectedKeyInfo.api_key === selectedKeyIdInfoView) {
    return (
      <KeyInfoView
        keyId={selectedKeyIdInfoView}
        keyData={selectedKeyInfo}
        teams={allTeams ?? []}
        onClose={() => setSelectedKeyIdInfoView(null)}
        backButtonText="Back to Logs"
      />
    );
  }

  return (
    <AutoRouterModelGroupsProvider>
      <div className="flex items-center justify-between mb-4">
        <h1 className="text-xl font-semibold">Request Logs</h1>
      </div>

      {isLiveTail && pagination.pageIndex === 0 && <LiveTailBanner onStop={() => setIsLiveTail(false)} />}

      <RequestLogsTable
        data={rows}
        rowCount={filteredLogs.total}
        isLoading={logsQuery.isLoading}
        isRefreshing={logsQuery.isFetching}
        pagination={pagination}
        onPaginationChange={setPagination}
        sorting={sorting}
        onSortingChange={handleSortingChange}
        columnFilters={columnFilters}
        onColumnFiltersChange={handleColumnFiltersChange}
        searchValue={searchTerm}
        onSearchChange={handleSearchChange}
        onRefresh={() => void logsQuery.refetch()}
        onRowClick={handleRowClick}
        onKeyHashClick={handleKeyHashClick}
        onSessionClick={handleSessionClick}
        teams={allTeams ?? []}
        logsWindow={logsWindow}
        toolbarChildren={
          <LogsTableToolbar
            startTime={startTime}
            onStartTimeChange={setStartTime}
            endTime={endTime}
            onEndTimeChange={setEndTime}
            isCustomDate={isCustomDate}
            onIsCustomDateChange={setIsCustomDate}
            selectedTimeInterval={selectedTimeInterval}
            onSelectedTimeIntervalChange={setSelectedTimeInterval}
            isLiveTail={isLiveTail}
            onIsLiveTailChange={setIsLiveTail}
            excludeInternalHealthChecks={excludeInternalHealthChecks}
            onExcludeInternalHealthChecksChange={handleExcludeInternalHealthChecksChange}
            onResetToFirstPage={resetToFirstPage}
            onResetFilters={handleResetFilters}
          />
        }
      />

      <LogDetailsDrawer
        open={isDrawerOpen}
        onClose={closeUrlLog}
        logEntry={displayLog}
        sessionId={displaySessionId}
        accessToken={accessToken}
        allLogs={rows}
        onSelectLog={handleSelectLog}
        startTime={moment(startTime).utc().format("YYYY-MM-DD HH:mm:ss")}
      />
    </AutoRouterModelGroupsProvider>
  );
}
