import { ArrowPathIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { t } from 'i18next';
import { useEffect, useState } from 'react';
import { toast, Toaster } from 'sonner';

import PrimaryButton from '../../../components/button/PrimaryButton';
import SelectDropdown from '../../../components/dropdown/SelectDropdown';
import SimpleInput from '../../../components/input/SimpleInput';
import Modal from '../../../components/modal/Modal';
import RichText from '../../../components/text/RichText';
import TextArea from '../../../components/text/TextArea';
import GetCWENameByLanguage from '../../../services/getCWEName';
import {
  postDescriptionCWE,
  updateVulnerability,
} from '../../../services/vulnerabilities';
import CVSSCalculator from '../components/CVSSCalculator';
import MultiCheckboxButton from '../components/MultiCheckboxButton';
import { useVulnState } from '../hooks/useVulnState';

type CWEData = {
  priority: number;
  label: string;
  score: number;
};

type Details = {
  locale: string;
  title?: string;
  vulnType?: string;
  description?: string;
  observation?: string;
  remediation?: string;
  cwes: string[];
  references: string[];
  customFields: string[];
};

type VulnerabilityData = {
  _id: string;
  cvssv3: string | null;
  priority?: number | '';
  remediationComplexity?: number | '';
  details: Details[];
  status?: number;
  category?: string | null;
  __v: number;
  createdAt?: string;
  updatedAt?: string;
};

type VulnerabilityDataProps = {
  priority?: number | '';
  remediationComplexity?: number | '';
  category?: string | null;
};

type ListItem = {
  id: number;
  value: string;
  label?: string;
  locale?: string;
};

type ListItemCategory = {
  id: number;
  value: string;
  label?: string;
  isNull?: boolean;
};

type EditVulnerabilityProps = {
  isOpen: boolean;
  handlerIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
  categories: ListItemCategory[];
  languages: ListItem[];
  types: ListItem[];
  refreshVulns: () => void;
  currentVuln: VulnerabilityData;
  handleOnSuccess: (message: string) => void;
};

type PostDescription = {
  vuln: string;
};

const EditVulnerability: React.FC<EditVulnerabilityProps> = ({
  isOpen,
  handlerIsOpen,
  categories,
  languages,
  types,
  refreshVulns,
  currentVuln,
  handleOnSuccess,
}) => {
  const {
    openModal,
    setOpenModal,
    changed,
    setChanged,
    categorySelected,
    setCategorySelected,
    categoryChanged,
    setCategoryChanged,
    selectedLanguage,
    setSelectedLanguage,
    selectedType,
    setSelectedType,
    typesFiltered,
    setTypesFiltered,
    cweLoading,
    setCweLoading,
    cweRecommendationSelected,
    setCweRecommendationSelected,
    cweRecommended,
    setCweRecommended,
  } = useVulnState({ currentVuln, languages, types });

  const [titleRequiredAlert, setTitleRequiredAlert] = useState<boolean>(false);

  const complexityOptions = [
    { id: 1, value: t('easy') },
    { id: 2, value: t('medium') },
    { id: 3, value: t('complex') },
  ];

  const priorityOptions = [
    { id: 1, value: t('low') },
    { id: 2, value: t('medium') },
    { id: 3, value: t('high') },
    { id: 4, value: t('urgent') },
  ];

  const [complexity, setComplexity] = useState<ListItem | null>(
    currentVuln.remediationComplexity
      ? complexityOptions[currentVuln.remediationComplexity - 1]
      : null,
  );

  const [priority, setPriority] = useState<ListItem | null>(
    currentVuln.priority ? priorityOptions[currentVuln.priority - 1] : null,
  );

  const [data, setData] = useState<VulnerabilityDataProps>({
    remediationComplexity: currentVuln.remediationComplexity ?? '',
    category: currentVuln.category ?? null,
    priority: currentVuln.priority ?? '',
  });

  const [details, setDetails] = useState<Details[]>(
    currentVuln.details.map(detailIter => ({
      locale: detailIter.locale,
      title: detailIter.title ?? '',
      vulnType: detailIter.vulnType ?? '',
      description: detailIter.description ?? '',
      observation: detailIter.observation ?? '',
      remediation: detailIter.remediation ?? '',
      cwes: detailIter.cwes,
      references: detailIter.references,
      customFields: detailIter.customFields,
    })),
  );

  const [detail, setDetail] = useState<Details>(details[0]);

  const [cvssStringInitial, setCvssStringInitial] = useState<string>(
    currentVuln.cvssv3 ?? '',
  );

  const closeSlidingPage = () => {
    setOpenModal(false);
    handlerIsOpen(false);
  };

  const checkChanged = () => {
    if (changed === false) {
      setChanged(true);
    }
  };

  const addNewDetail = (localeValue: string) => {
    const newDetail: Details = {
      locale: localeValue,
      title: '',
      vulnType: '',
      description: '',
      observation: '',
      remediation: '',
      cwes: [],
      references: [],
      customFields: [],
    };
    setDetail(newDetail);
  };

  const handlerCategoryChange = (item: ListItem) => {
    setCategorySelected(item);
    setCategoryChanged(true);
    checkChanged();
  };

  const handleTypeChange = (item: ListItem) => {
    checkChanged();
    setDetail(prevDetail => ({
      ...prevDetail,
      vulnType: item.value,
    }));
    setSelectedType(item);
  };

  const handleLanguageChange = (item: ListItem) => {
    checkChanged();
    setCweRecommendationSelected([]);
    setCweRecommended([]);

    const findLangItem = details.findIndex(
      detailLocale => detailLocale.locale === item.value,
    );

    if (findLangItem !== -1) {
      setDetail(details[findLangItem]);
      setSelectedType(
        types.find(
          typeIter => typeIter.locale === details[findLangItem].locale,
        ) ?? null,
      );
    } else {
      addNewDetail(item.value);
      setSelectedType(null);
    }
    setSelectedLanguage(item);

    setTypesFiltered(types.filter(typeIter => typeIter.locale === item.value));
  };

  const handleDropdownChange = (name: string, item: ListItem) => {
    checkChanged();
    setData(prevData => ({
      ...prevData,
      [name]: item.id,
    }));

    name === 'priority' ? setPriority(item) : setComplexity(item);
  };

  const handleInputChange = (field: string, value: string) => {
    checkChanged();
    setDetail(prevDetail => ({
      ...prevDetail,
      [field]:
        field === 'cwes' || field === 'references' ? value.split('\n') : value,
    }));
  };

  const handleCWERecomendation = async () => {
    if (detail.description === '' || detail.description === '<p><br></p>') {
      toast.error(t('err.descriptionRequired'));
      // Cambiar el estado de required
      return;
    }
    const descriptionCWE: PostDescription = {
      vuln: detail.description ?? '',
    };

    try {
      setCweLoading(true);
      setCweRecommendationSelected([]);
      const responseCWE = await postDescriptionCWE(descriptionCWE);
      const sortedResult = responseCWE.result.sort(
        (a: CWEData, b: CWEData) => b.score - a.score,
      );
      const recommendedCWEs = GetCWENameByLanguage(detail.locale, sortedResult);
      setCweRecommended(recommendedCWEs);
    } catch (error) {
      console.error('Error:', error);
      toast.error(t('err.failedCWERecommendation'));
    } finally {
      setCweLoading(false);
    }
  };

  const handlerSubmitCWE = () => {
    setDetail(prevDetail => ({
      ...prevDetail,
      cwes: [...cweRecommendationSelected, ...prevDetail.cwes],
    }));
    setCweRecommendationSelected([]);
    setCweRecommended([]);
  };

  useEffect(() => {
    const findLang = details.findIndex(
      detailLocale => detailLocale.locale === detail.locale,
    );

    if (findLang !== -1) {
      const updatedDetails = [...details];

      if (JSON.stringify(updatedDetails[findLang]) !== JSON.stringify(detail)) {
        updatedDetails[findLang] = { ...detail };
        setDetails(updatedDetails);
      }
    } else {
      details.push(detail);
    }
  }, [detail, details]);

  const updaterVulnData = () => {
    const filteredDetails: Details[] = details.map(
      ({ locale, cwes, references, customFields, ...rest }) => {
        const filteredRest = Object.fromEntries(
          Object.entries(rest).filter(([_, value]) => value !== ''),
        );

        return {
          locale,
          ...filteredRest,
          cwes,
          references,
          customFields,
        };
      },
    );

    const editvulnData: VulnerabilityData = {
      _id: currentVuln._id,
      __v: currentVuln.__v || 0,
      cvssv3: cvssStringInitial !== 'CVSS:3.1/' ? cvssStringInitial : null,
      status: currentVuln.status ?? 0,
      details: [...filteredDetails],
      ...(data.remediationComplexity && {
        remediationComplexity: data.remediationComplexity,
      }),
      ...(data.priority && {
        priority: data.priority,
      }),
      createdAt: currentVuln.createdAt ?? new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      ...(categoryChanged
        ? categorySelected?.isNull === true
          ? { category: null }
          : { category: categorySelected?.value }
        : data.category
          ? { category: data.category }
          : {}),
    };
    return editvulnData;
  };

  const handleSubmitUpdateVulnerability = async () => {
    if (!details.some(detail => detail.title !== '')) {
      toast.error(t('err.titleRequired'));
      setTitleRequiredAlert(true);
      return;
    }

    const editvulnData = updaterVulnData();

    try {
      const response = await updateVulnerability(editvulnData);
      if (response.status === 'success') {
        handleOnSuccess(t('msg.vulnerabilityUpdatedOk'));
      }
    } catch (error) {
      if (
        error instanceof Error &&
        error.message === 'Vulnerability title already exists'
      ) {
        toast.error(t('vulnerabilityTitleAlreadyExists'));
      } else {
        toast.error(t('failedCreateVulnerability'));
      }
      console.error('Error:', error);
      return;
    }

    refreshVulns();
    handlerIsOpen(!isOpen);
  };

  const handleCvssRecomendation = () => {
    if (detail.description === '' || detail.description === '<p><br></p>') {
      toast.error(t('err.descriptionRequired'));
      return '';
    } else {
      return detail.description ?? '';
    }
  };

  return (
    <>
      <div
        aria-hidden="true"
        className={`fixed inset-0 bg-black bg-opacity-50 transition-opacity duration-300 ${isOpen ? 'opacity-100' : 'opacity-0'}`}
        onClick={() => (changed ? setOpenModal(true) : closeSlidingPage())}
      />
      <div className="fixed z-10">
        <Modal
          cancelText={t('btn.stay')}
          disablehr
          isOpen={openModal}
          onCancel={() => setOpenModal(false)}
          onSubmit={closeSlidingPage}
          submitText={t('btn.confirm')}
          title={t('msg.doYouWantToLeave')}
        >
          <span />
        </Modal>
      </div>
      <Toaster />
      <div
        className={`fixed top-0 right-0 h-full w-1/2 bg-gray-700 shadow-lg transform transition-transform duration-300 ${
          isOpen ? 'translate-x-0 overflow-y-auto' : 'translate-x-full'
        }`}
      >
        <div className="ml-3 mt-2 flex justify-between items-center">
          <div className="flex items-center">
            <h4 className="text-xl font-bold p-1">{t('editVulnerability')}</h4>
            <span className="px-4 rounded-md border-0 text-white">
              {currentVuln.category ?? t('noCategory')}
            </span>
            <span className="w-px h-12 bg-gray-300" />
            <div className="mx-2 relative">
              <SelectDropdown
                items={categories}
                onChange={value => handlerCategoryChange(value)}
                placeholder={t('changeCategory')}
                selected={categorySelected}
                title=""
              />
            </div>
          </div>
          <button
            className="bg-transparent text-white p-2 rounded mx-3"
            onClick={() => (changed ? setOpenModal(true) : closeSlidingPage())}
            type="button"
          >
            <XMarkIcon className="h-6 w-6" />
          </button>
        </div>
        <hr className="h-1 my-3 bg-gray-600 border-0 rounded" />
        <div className="flex items-center">
          <div className="w-2/3 p-4">
            <SimpleInput
              id="title"
              label={t('title')}
              name="title"
              onChange={value => handleInputChange('title', value)}
              placeholder=""
              requiredAlert={titleRequiredAlert}
              requiredField={true}
              type="text"
              value={detail.title ?? ''}
            />
          </div>
          <div className="w-1/6 p-4">
            <SelectDropdown
              items={typesFiltered}
              onChange={handleTypeChange}
              placeholder=""
              selected={selectedType}
              title={t('type')}
            />
          </div>
          <div className="w-1/6 p-4 relative">
            <SelectDropdown
              items={languages}
              onChange={handleLanguageChange}
              selected={selectedLanguage}
              title={t('language')}
            />
          </div>
        </div>
        <div>
          <RichText
            label={t('description')}
            onChange={value => handleInputChange('description', value)}
            placeholder=""
            value={detail.description ?? ''}
          />
        </div>
        <div>
          <RichText
            label={t('observation')}
            onChange={value => handleInputChange('observation', value)}
            placeholder=""
            value={detail.observation ?? ''}
          />
        </div>
        <div>
          <RichText
            label={t('remediation')}
            onChange={value => handleInputChange('remediation', value)}
            placeholder=""
            value={detail.remediation ?? ''}
          />
        </div>
        <div className="mx-4 flex justify-center">
          <CVSSCalculator
            cvssStringInitial={cvssStringInitial}
            handleCvssChange={newCvssVector =>
              setCvssStringInitial(newCvssVector)
            }
            handleCvssRecomendation={handleCvssRecomendation}
          />
        </div>
        <div className="flex">
          <div className="w-1/2 p-4">
            <SelectDropdown
              items={complexityOptions}
              onChange={value =>
                handleDropdownChange('remediationComplexity', value)
              }
              selected={complexity}
              title={t('remediationComplexity')}
            />
          </div>
          <div className="w-1/2 p-4 relative">
            <SelectDropdown
              items={priorityOptions}
              onChange={value => handleDropdownChange('priority', value)}
              selected={priority}
              title={t('remediationPriority')}
            />
          </div>
        </div>
        <div className="m-4">
          <TextArea
            id="references"
            label={t('references')}
            name="references"
            onChange={value => handleInputChange('references', value)}
            placeholder=""
            rows={4}
            value={
              Array.isArray(detail.references)
                ? detail.references.join('\n')
                : detail.references
            }
          />
        </div>
        <div className="m-4">
          <TextArea
            id="cwes"
            label="CWEs"
            name="cwes"
            onChange={value => handleInputChange('cwes', value)}
            placeholder=""
            rows={4}
            value={
              Array.isArray(detail.cwes) ? detail.cwes.join('\n') : detail.cwes
            }
          />
        </div>
        <div className="mb-2 mx-4 flex">
          <PrimaryButton onClick={() => handleCWERecomendation()}>
            <span>{t('recommendCwe')}</span>
          </PrimaryButton>
          {cweLoading ? (
            <span className="ml-2">
              <ArrowPathIcon className="h-8 w-8 animate-spin text-blue-500" />
            </span>
          ) : null}
        </div>
        {cweRecommended.length > 0 ? (
          <div className="mx-4 mb-4">
            <MultiCheckboxButton
              cweRecommendationSelected={cweRecommendationSelected}
              cwesRecommended={cweRecommended}
              setCweRecommendationSelected={setCweRecommendationSelected}
            />
            {cweRecommendationSelected.length > 0 ? (
              <PrimaryButton
                onClick={() => {
                  handlerSubmitCWE();
                }}
              >
                {t('btn.confirmSelection')}
              </PrimaryButton>
            ) : null}
          </div>
        ) : null}
        <div className="mb-2 mx-4 flex justify-end">
          <PrimaryButton onClick={handleSubmitUpdateVulnerability}>
            <span>{t('editVulnerability')}</span>
          </PrimaryButton>
        </div>
      </div>
    </>
  );
};

export default EditVulnerability;
