import { Suspense, useMemo, type ReactNode } from "react";
import { Link } from "@tanstack/react-router";
import { useAtomRefresh, useAtomValue } from "@effect/atom-react";
import * as AsyncResult from "effect/unstable/reactivity/AsyncResult";
import { PlusIcon } from "lucide-react";
import type { Integration } from "@executor-js/sdk/shared";
import { useIntegrationPlugins, type IntegrationPlugin } from "@executor-js/sdk/client";
import { integrationsOptimisticAtom } from "../api/atoms";
import { trackEvent } from "../api/analytics";
import { McpInstallCard } from "../components/mcp-install-card";
import { WorkspaceAdminHint } from "../components/workspace-admin-hint";
import { Button } from "../components/button";
import { PageContainer, PageHeader } from "../components/page";
import {
  CardStack,
  CardStackContent,
  CardStackEntry,
  CardStackEntryActions,
  CardStackEntryContent,
  CardStackEntryDescription,
  CardStackEntryTitle,
  CardStackHeader,
} from "../components/card-stack";
import {
  IntegrationFavicon,
  integrationInferredUrl,
  integrationPresetIconUrl,
} from "../components/integration-favicon";
import { groupIntegrations, type IntegrationFamilyGroup } from "../lib/integration-grouping";
import { IntegrationHealthSummary } from "../components/integration-health-summary";
import { IntegrationIconWithAccount } from "../components/integration-icon-with-account";
import { Skeleton } from "../components/skeleton";
import { useExecutorDocumentTitle } from "../lib/document-title";
import { ErrorState } from "../components/error-state";
import { isAsyncResultLoading } from "../lib/async-result";
import { useCanCreateWorkspaceConnections } from "../multiplayer/use-admin-nav";

const KIND_TO_PLUGIN_KEY: Record<string, string> = {
  openapi: "openapi",
  mcp: "mcp",
  graphql: "graphql",
  googleDiscovery: "google",
};

// ---------------------------------------------------------------------------
// Page
// ---------------------------------------------------------------------------

export function IntegrationsPage() {
  useExecutorDocumentTitle("Integrations");
  const integrations = useAtomValue(integrationsOptimisticAtom);
  const refreshIntegrations = useAtomRefresh(integrationsOptimisticAtom);
  const canCreate = useCanCreateWorkspaceConnections();

  return (
    <PageContainer>
      <PageHeader
        title="Integrations"
        description="Tool providers available in this workspace."
        actions={
          canCreate ? (
            <Button asChild size="sm" className="gap-1.5">
              <Link
                to="/{-$orgSlug}/integrations/browse"
                onClick={() => trackEvent("integration_browse_opened", { via: "header" })}
              >
                <PlusIcon className="size-4" />
                Add integration
              </Link>
            </Button>
          ) : (
            <WorkspaceAdminHint allowed={false}>
              <Button disabled size="sm">
                <PlusIcon className="size-4" />
                Add integration
              </Button>
            </WorkspaceAdminHint>
          )
        }
      />

      <div className="mb-8">
        <McpInstallCard />
      </div>

      <div className="mb-8 border-t border-border/50" />

      {isAsyncResultLoading(integrations) ? (
        <IntegrationsGridSkeleton />
      ) : (
        AsyncResult.match(integrations, {
          onInitial: () => <IntegrationsGridSkeleton />,
          onFailure: () => (
            <ErrorState message="Failed to load integrations" onRetry={refreshIntegrations} />
          ),
          onSuccess: ({ value }) => {
            if (value.length === 0) {
              return <EmptyIntegrations canCreate={canCreate} />;
            }

            return (
              <div className="mb-8 space-y-3">
                <IntegrationGrid integrations={value} />
              </div>
            );
          },
        })
      )}
    </PageContainer>
  );
}

// ---------------------------------------------------------------------------
// Empty state
// ---------------------------------------------------------------------------

function EmptyIntegrations({ canCreate }: { readonly canCreate: boolean }) {
  return (
    <div className="mb-8 flex flex-col items-center justify-center rounded-2xl border border-dashed border-border py-16">
      <div className="mb-4 flex size-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground">
        <PlusIcon className="size-5" />
      </div>
      <p className="mb-1 text-[14px] font-medium text-foreground/70">No integrations yet</p>
      <p className="mb-5 text-[13px] text-muted-foreground/60">
        {canCreate
          ? "Connect an integration to start curating tools."
          : "Ask a workspace admin to add an integration."}
      </p>
      {canCreate ? (
        <Button asChild size="sm" className="gap-1.5">
          <Link
            to="/{-$orgSlug}/integrations/browse"
            onClick={() => trackEvent("integration_browse_opened", { via: "empty-state" })}
          >
            <PlusIcon className="size-4" />
            Add an integration
          </Link>
        </Button>
      ) : (
        <WorkspaceAdminHint allowed={false}>
          <Button disabled size="sm">
            <PlusIcon className="size-4" />
            Add an integration
          </Button>
        </WorkspaceAdminHint>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Integration grid — flat list of catalog integrations, click-through to detail
// ---------------------------------------------------------------------------

function IntegrationGrid(props: { integrations: readonly Integration[] }) {
  const integrationPlugins = useIntegrationPlugins();
  const pluginByKind = useMemo(() => {
    const out = new Map<string, IntegrationPlugin>();
    for (const p of integrationPlugins) out.set(p.key, p);
    return out;
  }, [integrationPlugins]);

  const items = useMemo(() => groupIntegrations(props.integrations), [props.integrations]);

  const renderEntry = (integration: Integration) => {
    const pluginKey = KIND_TO_PLUGIN_KEY[integration.kind] ?? integration.kind;
    const plugin = pluginByKind.get(pluginKey);
    const SummaryComponent = plugin?.summary;
    const slug = String(integration.slug);
    const name = integration.name || slug;
    return (
      <CardStackEntry key={slug} asChild searchText={`${name} ${slug} ${integration.kind}`}>
        <Link
          to="/{-$orgSlug}/integrations/$namespace"
          params={{ namespace: slug }}
          data-testid={`integration-entry-${slug}`}
        >
          <IntegrationIconWithAccount
            icon={integrationPresetIconUrl(
              { id: slug, kind: integration.kind, name, url: integration.displayUrl },
              integrationPlugins,
            )}
            integrationId={slug}
            url={integration.displayUrl ?? integrationInferredUrl({ id: slug, name }) ?? undefined}
          />
          <CardStackEntryContent>
            <CardStackEntryTitle>{name}</CardStackEntryTitle>
            <CardStackEntryDescription>{slug}</CardStackEntryDescription>
          </CardStackEntryContent>
          <CardStackEntryActions>
            {SummaryComponent && (
              <Suspense fallback={null}>
                <SummaryComponent integrationId={slug} />
              </Suspense>
            )}
            <IntegrationHealthSummary integration={integration.slug} />
          </CardStackEntryActions>
        </Link>
      </CardStackEntry>
    );
  };

  const rendered: ReactNode[] = [];
  let flatRun: Integration[] = [];
  const flushFlat = () => {
    if (flatRun.length === 0) return;
    const run = flatRun;
    flatRun = [];
    rendered.push(
      <CardStack key={`flat-${String(run[0]!.slug)}`} searchable>
        <CardStackContent>{run.map(renderEntry)}</CardStackContent>
      </CardStack>,
    );
  };

  for (const item of items) {
    if (item.type === "single") {
      flatRun.push(item.integration);
      continue;
    }
    flushFlat();
    rendered.push(
      <IntegrationFamilyGroupCard
        key={`group-${item.family}`}
        group={item}
        plugin={pluginByKind.get("openapi")}
        renderEntry={renderEntry}
      />,
    );
  }
  flushFlat();

  return <div className="space-y-3">{rendered}</div>;
}

function IntegrationFamilyGroupCard(props: {
  group: IntegrationFamilyGroup;
  plugin: IntegrationPlugin | undefined;
  renderEntry: (integration: Integration) => ReactNode;
}) {
  const { group, plugin, renderEntry } = props;
  const headerIcon =
    plugin?.presets?.find((preset) => preset.family === group.family && preset.icon)?.icon ?? null;
  return (
    <CardStack collapsible defaultOpen data-testid={`integration-group-${group.family}`}>
      <CardStackHeader>
        <span className="flex min-w-0 items-center gap-2">
          <span className="flex size-5 shrink-0 items-center justify-center">
            <IntegrationFavicon icon={headerIcon} size={16} />
          </span>
          <span className="truncate">{group.label}</span>
          <span className="shrink-0 font-mono text-xs font-normal text-muted-foreground">
            {group.members.length}
          </span>
        </span>
      </CardStackHeader>
      <CardStackContent>{group.members.map(renderEntry)}</CardStackContent>
    </CardStack>
  );
}

// ---------------------------------------------------------------------------
// Loading skeleton
// ---------------------------------------------------------------------------

function IntegrationsGridSkeleton() {
  return (
    <CardStack>
      <CardStackContent>
        {Array.from({ length: 4 }).map((_, i) => (
          <div key={i} className="flex items-center gap-3 px-4 py-3">
            <Skeleton className="size-8 shrink-0 rounded-md" />
            <div className="flex min-w-0 flex-1 flex-col gap-1.5">
              <Skeleton className="h-4" style={{ width: `${40 + ((i * 11) % 30)}%` }} />
              <Skeleton className="h-3" style={{ width: `${25 + ((i * 7) % 20)}%` }} />
            </div>
            <Skeleton className="h-5 w-16 rounded-full" />
          </div>
        ))}
      </CardStackContent>
    </CardStack>
  );
}
