import { ArrowRightIcon } from "@heroicons/react/20/solid";
import { CheckIcon } from "@heroicons/react/24/solid";
import { useLocation, useNavigation } from "@remix-run/react";
import { formatDuration } from "@trigger.dev/core/v3/utils/durations";
import { RunsIconExtraSmall } from "~/assets/icons/RunsIcon";
import { MiddleTruncate } from "~/components/primitives/MiddleTruncate";
import { DateTime } from "~/components/primitives/DateTime";
import { Paragraph } from "~/components/primitives/Paragraph";
import { PopoverMenuItem } from "~/components/primitives/Popover";
import { Spinner } from "~/components/primitives/Spinner";
import {
  Table,
  TableBlankRow,
  TableBody,
  TableCell,
  TableCellMenu,
  TableHeader,
  TableHeaderCell,
  TableRow,
} from "~/components/primitives/Table";
import { SimpleTooltip } from "~/components/primitives/Tooltip";
import { LiveTimer } from "~/components/runs/v3/LiveTimer";
import { RunTag } from "~/components/runs/v3/RunTag";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import {
  type SessionListItem,
  type SessionList,
} from "~/presenters/v3/SessionListPresenter.server";
import { v3RunPath, v3RunsPath, v3SessionPath } from "~/utils/pathBuilder";
import {
  descriptionForSessionStatus,
  SessionStatusCombo,
  allSessionStatuses,
} from "./SessionStatus";

type SessionsTableProps = Pick<SessionList, "sessions" | "filters" | "hasFilters"> & {
  showTopBorder?: boolean;
  stickyHeader?: boolean;
};

export function SessionsTable({
  sessions,
  hasFilters,
  showTopBorder = true,
  stickyHeader = false,
}: SessionsTableProps) {
  const navigation = useNavigation();
  const location = useLocation();
  const isLoading =
    navigation.state !== "idle" && navigation.location?.pathname === location.pathname;

  const organization = useOrganization();
  const project = useProject();
  const environment = useEnvironment();

  return (
    <Table
      className="max-h-full overflow-y-auto"
      showTopBorder={showTopBorder}
      stickyHeader={stickyHeader}
    >
      <TableHeader>
        <TableRow>
          <TableHeaderCell>ID</TableHeaderCell>
          <TableHeaderCell
            tooltip={
              <div className="flex flex-col divide-y divide-grid-dimmed">
                {allSessionStatuses.map((status) => (
                  <div
                    key={status}
                    className="grid grid-cols-[4rem_1fr] gap-x-3 py-2 first:pt-1 last:pb-1"
                  >
                    <div className="mb-0.5 flex items-center gap-1.5 whitespace-nowrap">
                      <SessionStatusCombo status={status} />
                    </div>
                    <Paragraph variant="extra-small" className="text-wrap! text-text-dimmed">
                      {descriptionForSessionStatus(status)}
                    </Paragraph>
                  </div>
                ))}
              </div>
            }
            disableTooltipHoverableContent
          >
            Status
          </TableHeaderCell>
          <TableHeaderCell>Type</TableHeaderCell>
          <TableHeaderCell>Agent ID</TableHeaderCell>
          <TableHeaderCell>Test</TableHeaderCell>
          <TableHeaderCell>Tags</TableHeaderCell>
          <TableHeaderCell>Created</TableHeaderCell>
          <TableHeaderCell>Duration</TableHeaderCell>
          <TableHeaderCell>
            <span className="sr-only">Actions</span>
          </TableHeaderCell>
        </TableRow>
      </TableHeader>
      <TableBody>
        {sessions.length === 0 ? (
          <TableBlankRow colSpan={9}>
            <div className="flex items-center justify-center">
              <Paragraph className="w-auto">
                {hasFilters
                  ? "No sessions match these filters"
                  : "No sessions in this environment yet"}
              </Paragraph>
            </div>
          </TableBlankRow>
        ) : (
          sessions.map((session) => {
            const runPath = session.currentRunFriendlyId
              ? v3RunPath(organization, project, environment, {
                  friendlyId: session.currentRunFriendlyId,
                })
              : undefined;

            const displayId = session.externalId ?? session.friendlyId;
            const sessionPath = v3SessionPath(organization, project, environment, {
              friendlyId: session.friendlyId,
            });
            const allRunsPath = v3RunsPath(organization, project, environment, {
              tags: [`chat:${displayId}`],
            });

            return (
              <TableRow key={session.id}>
                <TableCell to={sessionPath} isTabbableCell>
                  <div className="w-[28ch]">
                    <MiddleTruncate text={displayId} className="font-mono text-xs" />
                  </div>
                </TableCell>
                <TableCell to={sessionPath}>
                  <SimpleTooltip
                    content={descriptionForSessionStatus(session.status)}
                    disableHoverableContent
                    button={<SessionStatusCombo status={session.status} />}
                  />
                </TableCell>
                <TableCell to={sessionPath}>
                  <span className="font-mono text-xs">{session.type}</span>
                </TableCell>
                <TableCell to={sessionPath}>
                  <div className="w-[24ch]">
                    <MiddleTruncate text={session.taskIdentifier} className="font-mono text-xs" />
                  </div>
                </TableCell>
                <TableCell to={sessionPath}>
                  <span className="sr-only">{session.isTest ? "Yes" : "No"}</span>
                  {session.isTest ? (
                    <CheckIcon
                      aria-hidden
                      className="size-4 text-text-dimmed group-hover/table-row:text-text-bright"
                    />
                  ) : (
                    <span aria-hidden className="text-text-dimmed">
                      –
                    </span>
                  )}
                </TableCell>
                <TableCell to={sessionPath}>
                  {session.tags.length > 0 ? (
                    <div className="flex flex-wrap gap-1">
                      {session.tags.map((tag) => (
                        <RunTag key={tag} tag={tag} />
                      ))}
                    </div>
                  ) : (
                    <span className="text-text-dimmed">–</span>
                  )}
                </TableCell>
                <TableCell to={sessionPath}>
                  <DateTime date={session.createdAt} />
                </TableCell>
                <TableCell to={sessionPath} className="w-[1%]" actionClassName="pr-0 tabular-nums">
                  <SessionDuration session={session} />
                </TableCell>
                <SessionActionsCell runPath={runPath} allRunsPath={allRunsPath} />
              </TableRow>
            );
          })
        )}
        {isLoading && (
          <TableBlankRow
            colSpan={9}
            className="absolute left-0 top-0 flex h-full w-full items-center justify-center gap-2 bg-background-deep/90"
          >
            <Spinner /> <span className="text-text-dimmed">Loading…</span>
          </TableBlankRow>
        )}
      </TableBody>
    </Table>
  );
}

function SessionDuration({ session }: { session: SessionListItem }) {
  // Active sessions tick live; closed/expired sessions freeze at the
  // moment they ended (closedAt for explicit closes, expiresAt when the
  // TTL ran out without a close call).
  const endedAt =
    session.status === "CLOSED"
      ? session.closedAt
      : session.status === "EXPIRED"
        ? session.expiresAt
        : undefined;

  if (endedAt) {
    return (
      <>{formatDuration(new Date(session.createdAt), new Date(endedAt), { style: "short" })}</>
    );
  }

  return <LiveTimer startTime={new Date(session.createdAt)} />;
}

function SessionActionsCell({ runPath, allRunsPath }: { runPath?: string; allRunsPath: string }) {
  return (
    <TableCellMenu
      isSticky
      popoverContent={
        <>
          {runPath && (
            <PopoverMenuItem
              to={runPath}
              icon={ArrowRightIcon}
              leadingIconClassName="text-runs"
              title="View current run"
            />
          )}
          <PopoverMenuItem
            to={allRunsPath}
            icon={RunsIconExtraSmall}
            leadingIconClassName="text-runs"
            title="View all runs"
          />
        </>
      }
    />
  );
}
