import { useSuspenseQuery } from '@suspensive/react-query';
import { Suspense, useMemo, useState } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
import {
  Badge,
  Button,
  CircleSpinner,
  SlidingModal,
  SlidingModalCloseButton,
  SlidingModalContent,
  SlidingModalHeader,
} from 'ui-components';

import { ModelBasicNode } from '@/api/generated';
import { CopyButton, useCopyToClipboardState } from '@/components/CopyToClipboard';
import { DetailModal, useDetailModalState } from '@/components/detail-modal-stack';
import { DFLink } from '@/components/DFLink';
import { CopyLineIcon } from '@/components/icons/common/CopyLine';
import { PopOutIcon } from '@/components/icons/common/PopOut';
import { TimesIcon } from '@/components/icons/common/Times';
import { RemediationBlock } from '@/components/remediation/RemediationBlock';
import { RemediationButton } from '@/components/remediation/RemediationButton';
import { SeverityBadge, SeverityBadgeIcon } from '@/components/SeverityBadge';
import { VulnerabilityIcon } from '@/components/sideNavigation/icons/Vulnerability';
import { ResourceDetailModal } from '@/features/vulnerabilities/components/ResourceDetailModal';
import { queries } from '@/queries';
import { useTheme } from '@/theme/ThemeContext';
import { VulnerabilitySeverityType } from '@/types/common';
import { formatMilliseconds } from '@/utils/date';
import { getFieldsKeyValue } from '@/utils/detailsPanel';
import { replacebyUppercaseCharacters } from '@/utils/label';
import { usePageNavigation } from '@/utils/usePageNavigation';

function useGetCVEDetails() {
  const { cveId } = useParams();
  return useSuspenseQuery({
    ...queries.lookup.vulnerabilities({
      cveIds: [cveId ?? ''],
    }),
  });
}

function processLabel(labelKey: string) {
  return replacebyUppercaseCharacters(labelKey);
}

const timeFormatKey = {
  updated_at: 'updated_at',
};

const Header = ({
  setIsRemediationOpen,
}: {
  setIsRemediationOpen: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
  const { mode: theme } = useTheme();
  const {
    data: { data: vulnerabilities },
  } = useGetCVEDetails();

  const data = vulnerabilities.length ? vulnerabilities[0] : undefined;
  const { copy, isCopied } = useCopyToClipboardState();

  return (
    <SlidingModalHeader>
      <div className="pt-5 px-5 dark:bg-[linear-gradient(to_bottom,_#15253e_96px,_transparent_0)] bg-[linear-gradient(to_bottom,_#EEEEEE_96px,_transparent_0)]">
        <div className="flex items-center gap-2 pr-8 text-text-text-and-icon">
          <div className="h-4 w-4 shrink-0 dark:text-text-text-and-icon text-text-icon">
            <VulnerabilityIcon />
          </div>
          <h3 className="text-h3">{data?.cve_id ?? '-'}</h3>
          <RemediationButton
            className="ml-auto"
            type="button"
            onClick={(e) => {
              e.preventDefault();
              setIsRemediationOpen((prevOpen) => !prevOpen);
            }}
          />
        </div>
        <div className="mt-[18px] flex">
          <div className="px-4 flex flex-col gap-2">
            <div className="dark:bg-bg-left-nav bg-white p-2 rounded flex flex-col gap-1 dark:shadow-none shadow-[0_0_8px_0px_rgba(34,34,34,0.20)] min-w-[102px]">
              <div className="text-p9 text-text-text-and-icon whitespace-nowrap">
                CVSS score
              </div>
              <div className="text-h1 text-text-text-and-icon flex gap-x-2">
                <SeverityBadgeIcon
                  severity={(data?.cve_severity ?? '') as VulnerabilitySeverityType}
                  theme={theme}
                  className="h-9 w-9"
                />
                {data?.cve_cvss_score ?? 0}
              </div>
            </div>
            <div>
              <SeverityBadge
                className="w-full max-w-none"
                severity={data?.cve_severity ?? '-'}
              />
            </div>
          </div>
          <div className="flex-1">
            <div className="flex gap-2 justify-end">
              <Button
                variant="flat"
                size="sm"
                onClick={() => {
                  copy(JSON.stringify(data ?? {}));
                }}
                startIcon={<CopyLineIcon />}
              >
                {isCopied ? 'Copied JSON' : 'Copy JSON'}
              </Button>
            </div>
            <div className="mt-7 text-sm leading-5 text-text-text-and-icon max-h-64 overflow-y-auto">
              <ExpandableDescription description={data?.cve_description ?? '-'} />
            </div>
            {data?.cve_link?.length ? (
              <div className="mt-1">
                <DFLink
                  href={data.cve_link}
                  className="text-p2 flex items-center gap-3"
                  target="_blank"
                >
                  <span className="h-4 w-4 shrink-0">
                    <PopOutIcon />
                  </span>
                  <span
                    style={{
                      wordBreak: 'break-word',
                    }}
                  >
                    {data.cve_link}
                  </span>
                </DFLink>
              </div>
            ) : null}
          </div>
        </div>
      </div>
    </SlidingModalHeader>
  );
};

const DetailsComponent = ({
  isRemediationOpen,
  setIsRemediationOpen,
}: {
  isRemediationOpen: boolean;
  setIsRemediationOpen: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
  const {
    data: { data: cves },
  } = useGetCVEDetails();

  if (!cves.length) {
    return (
      <div className="flex items-center p-4 justify-center">
        <h3 className="text-p1a">No details found</h3>
      </div>
    );
  }
  const cve = { ...cves[0], epss_score: `${cves[0].epss_score}%` };

  if (isRemediationOpen) {
    return (
      <Suspense
        fallback={
          <div className="h-full w-full flex items-center justify-center">
            <CircleSpinner size="lg" />
          </div>
        }
      >
        <RemediationBlock
          meta={{
            type: 'cve',
            args: {
              cve_caused_by_package: cve.cve_caused_by_package,
              cve_id: cve.cve_id,
              cve_type: cve.cve_type,
              query_type: 'remediation',
            },
          }}
          onBackButtonClick={() => setIsRemediationOpen(false)}
        />
      </Suspense>
    );
  }

  const keyValues = getFieldsKeyValue(cve ?? {}, {
    hiddenFields: [
      'cve_id',
      'cve_cvss_score',
      'cve_description',
      'cve_link',
      'cve_severity',
      'cve_overall_score',
      'node_id',
      'rule_id',
      'exploit_poc',
      'resources',
      'urls',
    ],
    priorityFields: [
      'cve_caused_by_package',
      'cve_caused_by_package_path',
      'cve_fixed_in',
      'cve_attack_vector',
      'parsed_attack_vector',
      'epss_score',
      'cve_type',
      'cisa_kev',
      'has_live_connection',
      'cve_container_layer',
      'masked',
      'updated_at',
    ],
  });

  return (
    <div>
      <div className="flex flex-wrap gap-y-[30px] gap-x-[14px] py-[18px] px-5">
        {keyValues.map(({ key, value }) => {
          const label = processLabel(key);
          let valueAsStr = '-';
          if (Array.isArray(value)) {
            valueAsStr = value.join(', ');
          } else if (typeof value === 'string') {
            valueAsStr = value;
          } else {
            valueAsStr = String(value);
          }
          return (
            <div
              key={key}
              className="flex flex-col grow basis-[45%] max-w-full gap-1 group"
            >
              <div className="flex relative">
                <div className="text-p3 text-text-text-and-icon first-letter:capitalize">
                  {label}
                </div>
                <CopyButton value={valueAsStr} className="hidden group-hover:block" />
              </div>
              <div className="text-p1 dark:text-text-input-value text-text-text-and-icon break-words">
                {key in timeFormatKey ? formatMilliseconds(+valueAsStr) : valueAsStr}
              </div>
            </div>
          );
        })}

        {cve.resources?.length ? <ResourcesMeta resources={cve.resources} /> : null}

        <div className="flex flex-col grow basis-[45%] max-w-full gap-1">
          <div className="text-p3 text-text-text-and-icon">Exploit POC</div>
          <div className="text-p1">
            {cve.exploit_poc.length ? (
              <DFLink
                href={cve.exploit_poc}
                className="text-p2 flex items-center gap-3"
                target="_blank"
              >
                <span className="h-4 w-4 shrink-0">
                  <PopOutIcon />
                </span>
                <span className="truncate">{cve.exploit_poc}</span>
              </DFLink>
            ) : (
              '-'
            )}
          </div>
        </div>

        {cve.urls?.length ? (
          <div className="flex flex-col grow basis-[45%] max-w-full gap-1">
            <div className="text-p3 text-text-text-and-icon">URLs</div>
            <div className="text-p1">
              {cve.urls.map((url) => {
                return (
                  <DFLink
                    key={url}
                    href={url}
                    className="text-p2 flex items-center gap-3"
                    target="_blank"
                  >
                    <span className="h-4 w-4 shrink-0">
                      <PopOutIcon />
                    </span>
                    <span className="truncate">{url}</span>
                  </DFLink>
                );
              })}
            </div>
          </div>
        ) : null}
      </div>
    </div>
  );
};

const ResourcesMeta = ({ resources }: { resources: ModelBasicNode[] }) => {
  const { detailModalItem, setDetailModalItem } = useDetailModalState();
  const [showResourceModal, setShowResourceModal] = useState({
    resource: '',
    show: false,
  });
  return (
    <div className="flex flex-col grow basis-[100%] max-w-full gap-1 group">
      <div className="basis-[45%] flex relative">
        <div className="flex gap-2 items-center">
          <div className="text-p3 text-text-text-and-icon">Resources</div>
        </div>
        <CopyButton
          value={JSON.stringify(resources)}
          className="hidden group-hover:block"
        />
      </div>
      <div className="text-p1 flex flex-col">
        {showResourceModal.show ? (
          <ResourceDetailModal
            open={showResourceModal.show}
            onClose={() => {
              setShowResourceModal({
                show: false,
                resource: '',
              });
            }}
            nodeId={showResourceModal.resource}
          />
        ) : null}
        {resources
          .filter((resource) => {
            return resource.node_type !== 'container_image' && resource.active;
          })
          .map((resource) => {
            if (!resource.node_id || !resource.node_type) {
              return null;
            }
            let redirectPath = '';
            if (resource.node_type === 'host') {
              redirectPath = `host/table?hosts=${resource.node_id}`;
            } else if (resource.node_type === 'container') {
              redirectPath = `container/table?containers=${resource.node_id}`;
            }
            return (
              <DFLink
                key={resource.node_id}
                to={`/inventory/compute/${redirectPath}`}
                target="_blank"
                rel="noreferrer"
                className="text-p2 flex items-center gap-3"
                onClick={(e) => {
                  if (
                    resource.node_type === 'container' ||
                    resource.node_type === 'host'
                  ) {
                    e.preventDefault();
                    setDetailModalItem({
                      kind: resource.node_type,
                      nodeId: resource.node_id,
                    });
                  }
                }}
              >
                <span className="h-4 w-4 shrink-0">
                  <PopOutIcon />
                </span>
                <span className="truncate">{resource.name}</span>
              </DFLink>
            );
          })}
        {resources
          .filter((resource) => {
            return resource.node_type === 'container_image' && resource.active;
          })
          .map((resource, index) => {
            return (
              <>
                <button
                  type="button"
                  key={resource.node_id + index}
                  onClick={() => {
                    setShowResourceModal({
                      show: true,
                      resource: resource.node_id,
                    });
                  }}
                  className="text-p1 w-fit text-accent-accent"
                >
                  {resource.name}
                </button>
              </>
            );
          })}
        {resources
          .filter((resource) => {
            return !resource.active;
          })
          .map((resource) => {
            return (
              <span key={resource.node_id} className="truncate">
                {resource.name} (Inactive)
              </span>
            );
          })}
      </div>
      {detailModalItem ? (
        <DetailModal
          itemInfo={detailModalItem}
          onItemClose={() => setDetailModalItem(null)}
        />
      ) : null}
    </div>
  );
};

const VulnerabilityDetails = () => {
  const { navigate } = usePageNavigation();
  const [searchParams] = useSearchParams();
  const [isRemediationOpen, setIsRemediationOpen] = useState(false);

  return (
    <SlidingModal
      open={true}
      onOpenChange={() => {
        navigate(`..?${searchParams.toString()}`);
      }}
      size="xxl"
    >
      <SlidingModalCloseButton />
      <Suspense
        fallback={
          <SlidingModalContent>
            <div className="h-full w-full flex items-center justify-center">
              <CircleSpinner size="lg" />
            </div>
          </SlidingModalContent>
        }
      >
        <Header setIsRemediationOpen={setIsRemediationOpen} />
        <SlidingModalContent>
          <div className="h-full">
            <DetailsComponent
              isRemediationOpen={isRemediationOpen}
              setIsRemediationOpen={setIsRemediationOpen}
            />
          </div>
        </SlidingModalContent>
      </Suspense>
    </SlidingModal>
  );
};

const DESCRIPTION_SHORT_LENGTH = 150;
const ExpandableDescription = ({ description }: { description: string }) => {
  const [isExpanded, setIsExpanded] = useState(false);
  const shouldShowExpand = useMemo(() => {
    return description.length > DESCRIPTION_SHORT_LENGTH;
  }, [description]);
  return (
    <div>
      {isExpanded
        ? description
        : `${description.slice(0, DESCRIPTION_SHORT_LENGTH - 2)}${
            shouldShowExpand ? '...' : ''
          }`}
      {shouldShowExpand ? (
        <>
          &nbsp;
          <button
            className="text-text-link"
            type="button"
            onClick={() => setIsExpanded((prev) => !prev)}
          >
            {isExpanded ? 'less' : 'more'}
          </button>
        </>
      ) : null}
    </div>
  );
};

export const module = {
  element: <VulnerabilityDetails />,
};
