import React, { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Col, Row, Spacer } from '@freecodecamp/ui';

import {
  certificationCollectionSuperBlocks,
  chapterBasedSuperBlocks,
  SuperBlocks
} from '@freecodecamp/shared/config/curriculum';
import type {
  ChapterBasedSuperBlockStructure,
  User
} from '../../../redux/prop-types';
import type {
  BlockLabel,
  BlockLayouts
} from '@freecodecamp/shared/config/blocks';
import { SuperBlockIcon } from '../../../assets/superblock-icon';
import { Link } from '../../../components/helpers';
import {
  certSlugTypeMap,
  certificationRequirements,
  superBlockToCertMap
} from '@freecodecamp/shared/config/certification-settings';
import CheckMark from './check-mark';

import Block from './block';
import CertChallenge from './cert-challenge';
import { SuperBlockAccordion } from './super-block-accordion';
import './super-block-accordion.css';
import SuperBlockSearch from './super-block-search';

type Challenge = {
  block: string;
  blockLabel?: BlockLabel;
  blockLayout: BlockLayouts;
  chapter: string;
  challengeType: number;
  dashedName: string;
  fields: { slug: string };
  id: string;
  module: string;
  order: number;
  superBlock: SuperBlocks;
  title: string;
};

type SuperBlockMapProps = {
  completedChallengeIds: string[];
  disabledBlocks: string[];
  initialExpandedBlock: string;
  showCertification: boolean;
  structure?: ChapterBasedSuperBlockStructure;
  superBlock: SuperBlocks;
  superBlockChallenges: Challenge[];
  user: User | null;
};

const BlockList = ({
  disabledBlocks,
  showCertification,
  superBlock,
  superBlockChallenges,
  user,
  expandAll = false
}: {
  disabledBlocks: string[];
  showCertification: boolean;
  superBlock: SuperBlocks;
  superBlockChallenges: Challenge[];
  user: User | null;
  expandAll?: boolean;
}) => {
  const visibleBlocks = useMemo(() => {
    const uniqueBlocks = Array.from(
      new Set(superBlockChallenges.map(({ block }) => block))
    );

    return uniqueBlocks.filter(block => !disabledBlocks.includes(block));
  }, [disabledBlocks, superBlockChallenges]);

  return (
    <div className='block-ui'>
      {visibleBlocks.map(block => {
        const blockChallenges = superBlockChallenges.filter(
          challenge => challenge.block === block
        );
        const blockLabel = blockChallenges[0]?.blockLabel ?? null;

        if (!blockChallenges.length) return null;

        return (
          <Block
            key={block}
            block={block}
            blockLabel={blockLabel}
            challenges={blockChallenges}
            superBlock={superBlock}
            expandAll={expandAll}
          />
        );
      })}
      {showCertification && !!user && (
        <CertChallenge superBlock={superBlock} user={user} />
      )}
    </div>
  );
};

export const SuperBlockMap = ({
  completedChallengeIds,
  disabledBlocks,
  initialExpandedBlock,
  showCertification,
  structure,
  superBlock,
  superBlockChallenges,
  user
}: SuperBlockMapProps) => {
  const { t } = useTranslation();
  const [searchTerm, setSearchTerm] = useState('');
  const isSearching = searchTerm.length > 0;

  const filteredChallenges = useMemo(() => {
    if (!isSearching) return superBlockChallenges;
    return superBlockChallenges.filter(challenge => {
      const challengeTitle = challenge.title.toLowerCase();
      const blockTitle = t(
        `intro:${superBlock}.blocks.${challenge.block}.title`
      ).toLowerCase();
      return (
        challengeTitle.includes(searchTerm) || blockTitle.includes(searchTerm)
      );
    });
  }, [isSearching, searchTerm, superBlockChallenges, superBlock, t]);

  if (chapterBasedSuperBlocks.includes(superBlock)) {
    if (!structure) return null;

    const getRequirementItems = () => {
      const certificationForSuperBlock = superBlockToCertMap[superBlock];
      const requirementsLookup = certificationRequirements as Partial<
        Record<string, SuperBlocks[]>
      >;
      const requirements: SuperBlocks[] =
        (certificationForSuperBlock &&
          requirementsLookup[certificationForSuperBlock]) ??
        [];

      const requirementItems = requirements.map((requirement: SuperBlocks) => {
        const requirementTitle = t(`intro:${requirement}.title`);
        const requirementLink = `/learn/${requirement}/`;

        const certSlug = superBlockToCertMap[requirement];
        const certFlagKey = certSlug ? certSlugTypeMap[certSlug] : undefined;
        const isRequirementComplete = Boolean(
          certFlagKey && user?.[certFlagKey]
        );

        return (
          <li className='chapter requirement' key={requirement}>
            <Link
              className='chapter-button'
              data-playwright-test-label='requirement-button'
              to={requirementLink}
            >
              <div className='chapter-button-left'>
                <span className='checkmark-wrap chapter-checkmark-wrap'>
                  <CheckMark isCompleted={isRequirementComplete} />
                </span>
                <SuperBlockIcon className='map-icon' superBlock={requirement} />
                {requirementTitle}
              </div>
            </Link>
          </li>
        );
      });

      return requirementItems;
    };

    return (
      <>
        <Row>
          <Col md={8} mdOffset={2} sm={10} smOffset={1} xs={12}>
            <SuperBlockSearch
              onSearch={setSearchTerm}
              resultCount={filteredChallenges.length}
              isSearching={isSearching}
            />
          </Col>
        </Row>
        {certificationCollectionSuperBlocks.includes(superBlock) && (
          <>
            <ul className='super-block-accordion requirement-list'>
              {getRequirementItems()}
            </ul>
            <Spacer size='m' />
            <h2 className='text-center big-subheading'>
              {t(`intro:misc-text.courses`)}
            </h2>
            <Spacer size='m' />
          </>
        )}

        <SuperBlockAccordion
          challenges={filteredChallenges}
          superBlock={superBlock}
          structure={structure}
          chosenBlock={initialExpandedBlock}
          completedChallengeIds={completedChallengeIds}
          expandAll={isSearching}
        />
      </>
    );
  }

  return (
    <>
      <Row>
        <Col sm={10} smOffset={1} xs={12}>
          <SuperBlockSearch
            onSearch={setSearchTerm}
            resultCount={filteredChallenges.length}
            isSearching={isSearching}
          />
        </Col>
      </Row>
      <BlockList
        disabledBlocks={disabledBlocks}
        showCertification={showCertification}
        superBlock={superBlock}
        superBlockChallenges={filteredChallenges}
        user={user}
        expandAll={isSearching}
      />
    </>
  );
};

SuperBlockMap.displayName = 'SuperBlockMap';

export default SuperBlockMap;
