import { Suspense } from "react";

import { getAllProviders } from "@/actions/providers";
import { getScans } from "@/actions/scans";
import { auth } from "@/auth.config";
import { MutedFindingsConfigButton } from "@/components/providers";
import {
  NoProvidersAdded,
  NoProvidersConnected,
  ScansFilters,
} from "@/components/scans";
import { LaunchScanWorkflow } from "@/components/scans/launch-workflow";
import { SkeletonTableScans } from "@/components/scans/table";
import { ScansTableWithPolling } from "@/components/scans/table/scans";
import { ContentLayout } from "@/components/ui";
import { CustomBanner } from "@/components/ui/custom/custom-banner";
import {
  createProviderDetailsMapping,
  extractProviderUIDs,
} from "@/lib/provider-helpers";
import {
  ExpandedScanData,
  ProviderProps,
  ScanProps,
  SearchParamsProps,
} from "@/types";

export default async function Scans({
  searchParams,
}: {
  searchParams: Promise<SearchParamsProps>;
}) {
  const session = await auth();
  const resolvedSearchParams = await searchParams;
  const filteredParams = { ...resolvedSearchParams };
  delete filteredParams.scanId;

  const [providersData, completedScansData] = await Promise.all([
    getAllProviders(),
    getScans({
      filters: { "filter[state]": "completed" },
      pageSize: 50,
      fields: { scans: "name,completed_at,provider" },
      include: "provider",
    }),
  ]);

  const completedScans: ExpandedScanData[] = (completedScansData?.data ?? [])
    .map((scan: ScanProps) => {
      const providerId = scan.relationships?.provider?.data?.id;
      const providerData = completedScansData?.included?.find(
        (item: { type: string; id: string }) =>
          item.type === "providers" && item.id === providerId,
      );
      if (!providerData) return null;
      return {
        ...scan,
        providerInfo: {
          provider: providerData.attributes.provider,
          uid: providerData.attributes.uid,
          alias: providerData.attributes.alias,
        },
      };
    })
    .filter(Boolean) as ExpandedScanData[];

  const providerInfo =
    providersData?.data
      ?.filter(
        (provider: ProviderProps) =>
          provider.attributes.connection.connected === true,
      )
      .map((provider: ProviderProps) => ({
        providerId: provider.id,
        alias: provider.attributes.alias,
        providerType: provider.attributes.provider,
        uid: provider.attributes.uid,
        connected: provider.attributes.connection.connected,
      })) || [];

  const thereIsNoProviders =
    !providersData?.data || providersData.data.length === 0;

  const thereIsNoProvidersConnected = providersData?.data?.every(
    (provider: ProviderProps) => !provider.attributes.connection.connected,
  );

  const hasManageScansPermission = session?.user?.permissions?.manage_scans;

  // Extract provider UIDs and create provider details mapping for filtering
  const providerUIDs = providersData ? extractProviderUIDs(providersData) : [];
  const providerDetails = providersData
    ? createProviderDetailsMapping(providerUIDs, providersData)
    : [];

  if (thereIsNoProviders) {
    return (
      <ContentLayout title="Scans" icon="lucide:timer">
        <NoProvidersAdded />
      </ContentLayout>
    );
  }

  return (
    <ContentLayout title="Scans" icon="lucide:timer">
      <>
        <>
          {!hasManageScansPermission ? (
            <CustomBanner
              title={"Access Denied"}
              message={"You don't have permission to launch the scan."}
            />
          ) : thereIsNoProvidersConnected ? (
            <>
              <NoProvidersConnected />
            </>
          ) : (
            <LaunchScanWorkflow providers={providerInfo} />
          )}
        </>
        <div className="flex flex-col gap-6">
          <ScansFilters
            providerUIDs={providerUIDs}
            providerDetails={providerDetails}
            completedScans={completedScans}
          />
          <div className="flex items-center justify-end">
            <MutedFindingsConfigButton />
          </div>
          <Suspense fallback={<SkeletonTableScans />}>
            <SSRDataTableScans searchParams={resolvedSearchParams} />
          </Suspense>
        </div>
      </>
    </ContentLayout>
  );
}

const SSRDataTableScans = async ({
  searchParams,
}: {
  searchParams: SearchParamsProps;
}) => {
  const page = parseInt(searchParams.page?.toString() || "1", 10);
  const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10);
  const sort = searchParams.sort?.toString();

  // Extract all filter parameters, excluding scanId
  const filters = Object.fromEntries(
    Object.entries(searchParams).filter(
      ([key]) => key.startsWith("filter[") && key !== "scanId",
    ),
  );

  // Extract query from filters
  const query = (filters["filter[search]"] as string) || "";

  // Fetch scans data with provider information included
  const scansData = await getScans({
    query,
    page,
    sort,
    filters,
    pageSize,
    include: "provider",
  });

  const scans = scansData?.data;
  const included = scansData?.included;
  const meta = scansData && "meta" in scansData ? scansData.meta : undefined;

  const expandedScansData =
    scans?.map((scan: ScanProps) => {
      const providerId = scan.relationships?.provider?.data?.id;

      if (!providerId) {
        return { ...scan, providerInfo: null };
      }

      // Find the provider data in the included array
      const providerData = included?.find(
        (item: { type: string; id: string }) =>
          item.type === "providers" && item.id === providerId,
      );

      if (!providerData) {
        return { ...scan, providerInfo: null };
      }

      return {
        ...scan,
        providerInfo: {
          provider: providerData.attributes.provider,
          uid: providerData.attributes.uid,
          alias: providerData.attributes.alias,
        },
      };
    }) || [];

  return (
    <ScansTableWithPolling
      initialData={expandedScansData}
      initialMeta={meta}
      searchParams={searchParams}
    />
  );
};
