import { Suspense } from "react";

import {
  adaptFindingGroupsResponse,
  getFindingGroups,
  getLatestFindingGroups,
} from "@/actions/finding-groups";
import { getLatestMetadataInfo, getMetadataInfo } from "@/actions/findings";
import { getAllProviderGroups } from "@/actions/manage-groups/manage-groups";
import { getAllProviders } from "@/actions/providers";
import { getScan, getScans } from "@/actions/scans";
import { SeedFromFindingsButton } from "@/app/(prowler)/alerts/_components";
import { FindingsFilters } from "@/components/findings/findings-filters";
import {
  FindingsGroupTable,
  SkeletonTableFindings,
} from "@/components/findings/table";
import { ContentLayout } from "@/components/shadcn/content-layout";
import { FilterTransitionWrapper } from "@/contexts";
import {
  applyDefaultMutedFilter,
  createScanDetailsMapping,
  extractFiltersAndQuery,
  extractSortAndKey,
  hasDateOrScanFilter,
} from "@/lib";
import { resolveFindingScanDateFilters } from "@/lib/findings-scan-filters";
import { isCloud } from "@/lib/shared/env";
import { ScanEntity, ScanProps } from "@/types";
import { SearchParamsProps } from "@/types/components";

export default async function Findings({
  searchParams,
}: {
  searchParams: Promise<SearchParamsProps>;
}) {
  const resolvedSearchParams = await searchParams;
  const { encodedSort } = extractSortAndKey(resolvedSearchParams);
  const { filters, query } = extractFiltersAndQuery(resolvedSearchParams);

  const [providersData, providerGroupsData, scansData] = await Promise.all([
    getAllProviders(),
    getAllProviderGroups(),
    getScans({ pageSize: 50 }),
  ]);

  const filtersWithScanDates = await resolveFindingScanDateFilters({
    filters,
    scans: scansData?.data || [],
    loadScan: async (scanId: string) => {
      const response = await getScan(scanId);
      return response?.data;
    },
  });
  const resolvedFilters = applyDefaultMutedFilter(filtersWithScanDates);
  const hasHistoricalData = hasDateOrScanFilter(filtersWithScanDates);
  const metadataInfoData = await (
    hasHistoricalData ? getMetadataInfo : getLatestMetadataInfo
  )({
    query,
    sort: encodedSort,
    filters: resolvedFilters,
  });

  const uniqueRegions = metadataInfoData?.data?.attributes?.regions || [];
  const uniqueServices = metadataInfoData?.data?.attributes?.services || [];
  const uniqueResourceTypes =
    metadataInfoData?.data?.attributes?.resource_types || [];
  const uniqueCategories = metadataInfoData?.data?.attributes?.categories || [];
  const uniqueGroups = metadataInfoData?.data?.attributes?.groups || [];

  const completedScans = scansData?.data?.filter(
    (scan: ScanProps) =>
      scan.attributes.state === "completed" &&
      scan.attributes.unique_resource_count > 1,
  );

  const completedScanIds =
    completedScans?.map((scan: ScanProps) => scan.id) || [];
  const onboardingAction =
    completedScanIds.length > 0
      ? { flowId: "explore-findings" }
      : {
          flowId: "explore-findings",
          fallbackFlowId: "view-first-scan",
          useFallback: true,
        };

  const scanDetails = createScanDetailsMapping(
    completedScans || [],
    providersData,
  ) as { [uid: string]: ScanEntity }[];
  const alertsEnabled = isCloud();

  return (
    <ContentLayout
      title="Findings"
      icon="lucide:tag"
      onboardingAction={onboardingAction}
    >
      <FilterTransitionWrapper>
        <div className="mb-6">
          <FindingsFilters
            providers={providersData?.data || []}
            providerGroups={providerGroupsData?.data || []}
            completedScanIds={completedScanIds}
            scanDetails={scanDetails}
            uniqueRegions={uniqueRegions}
            uniqueServices={uniqueServices}
            uniqueResourceTypes={uniqueResourceTypes}
            uniqueCategories={uniqueCategories}
            uniqueGroups={uniqueGroups}
            trailingControls={
              <SeedFromFindingsButton
                filterBag={filters}
                providers={providersData?.data || []}
                scans={scanDetails}
                uniqueRegions={uniqueRegions}
                uniqueServices={uniqueServices}
                uniqueResourceTypes={uniqueResourceTypes}
                uniqueCategories={uniqueCategories}
                uniqueGroups={uniqueGroups}
                isCloudEnabled={alertsEnabled}
              />
            }
          />
        </div>
        <Suspense fallback={<SkeletonTableFindings />}>
          <SSRDataTable
            searchParams={resolvedSearchParams}
            filters={resolvedFilters}
          />
        </Suspense>
      </FilterTransitionWrapper>
    </ContentLayout>
  );
}

const SSRDataTable = async ({
  searchParams,
  filters,
}: {
  searchParams: SearchParamsProps;
  filters: Record<string, string>;
}) => {
  const page = parseInt(searchParams.page?.toString() || "1", 10);
  const pageSize = parseInt(searchParams.pageSize?.toString() || "10", 10);

  const { encodedSort } = extractSortAndKey(searchParams);
  const hasHistoricalData = hasDateOrScanFilter(filters);

  const fetchFindingGroups = hasHistoricalData
    ? getFindingGroups
    : getLatestFindingGroups;

  const findingGroupsData = await fetchFindingGroups({
    page,
    ...(encodedSort && { sort: encodedSort }),
    filters,
    pageSize,
  });

  const groups = adaptFindingGroupsResponse(findingGroupsData);
  // Key resets client state (selection, drill-down) when data changes.
  const groupKey = groups.map((g) => g.id).join(",");

  return (
    <>
      {findingGroupsData?.errors?.length > 0 && (
        <div className="mb-4 flex rounded-lg border border-red-500 bg-red-100 p-2 text-sm text-red-700">
          <p className="mr-2 font-semibold">Error:</p>
          <p>{findingGroupsData.errors[0].detail}</p>
        </div>
      )}
      <FindingsGroupTable
        key={groupKey}
        data={groups}
        metadata={findingGroupsData?.meta}
        resolvedFilters={filters}
        hasHistoricalData={hasHistoricalData}
      />
    </>
  );
};
