import React, { useEffect, useState } from 'react';
import store from 'store';
import ShowClassic from '../templates/Challenges/classic/show';
import { Loader } from '../components/helpers';
import {
  DailyCodingChallengeLanguages,
  DailyCodingChallengeNode,
  DailyCodingChallengePageContext
} from '../redux/prop-types';
import DailyCodingChallengeNotFound from '../components/daily-coding-challenge/not-found';
import { apiLocation } from '../../config/env.json';
import { isValidDateString } from '../components/daily-coding-challenge/helpers';
import {
  validateDailyCodingChallengeSchema,
  type DailyCodingChallengeFromDb
} from '../utils/daily-coding-challenge-validator';

interface DailyCodingChallengeLanguageData {
  data: {
    challengeNode: DailyCodingChallengeNode;
  };
  pageContext: DailyCodingChallengePageContext;
}

interface DailyCodingChallengeDataFormatted {
  javascript: DailyCodingChallengeLanguageData;
  python: DailyCodingChallengeLanguageData;
}

// This is not included in the data from the DB (Daily Challenge API) - so we add it in
function formatDescription(str: string) {
  return `<section id="description">\n${str}\n</section>`;
}

function formatChallengeData({
  date,
  id,
  challengeNumber,
  title,
  description,
  javascript,
  python
}: DailyCodingChallengeFromDb) {
  const baseChallengeProps = {
    date,
    id,
    challengeNumber,
    title,
    description: formatDescription(description),
    superBlock: 'daily-coding-challenge',
    block: 'daily-coding-challenge',
    usesMultifileEditor: true,

    // props to satisfy the show classic component
    instructions: '',
    demoType: null,
    hooks: undefined,
    hasEditableBoundaries: false,
    forumTopicId: undefined,
    notes: '',
    videoUrl: undefined,
    translationPending: false
  };

  const pageContext = {
    challengeMeta: {
      id,
      superBlock: 'daily-coding-challenge',
      block: 'daily-coding-challenge',
      disableLoopProtectTests: true,
      dashedName: `challenge-${challengeNumber}`,

      // props to satisfy the show classic component
      isFirstStep: false,
      nextChallegePath: undefined,
      prevChallengePath: undefined,
      disableLoopProtectPreview: false
    },

    // props to satisfy the show classic component
    projectPreview: {
      challengeData: undefined
    }
  };

  const props = {
    javascript: {
      data: {
        challengeNode: {
          challenge: {
            ...baseChallengeProps,
            helpCategory: 'JavaScript',
            challengeType: 28,
            tests: javascript.tests,
            challengeFiles: [
              {
                name: 'script',
                ext: 'js',
                contents: javascript.challengeFiles[0].contents,
                path: '',
                history: ['script.js'],
                fileKey: 'scriptjs'
              }
            ]
          }
        }
      },
      pageContext
    },
    python: {
      data: {
        challengeNode: {
          challenge: {
            ...baseChallengeProps,
            helpCategory: 'Python',
            challengeType: 29,
            tests: python.tests,
            challengeFiles: [
              {
                fileKey: 'mainpy',
                ext: 'py',
                name: 'main',
                contents: python.challengeFiles[0].contents,
                path: '',
                editableRegionBoundaries: [],
                history: ['main.py']
              }
            ]
          }
        }
      },
      pageContext
    }
  };

  return props;
}

function ShowDailyCodingChallenge({ date }: { date: string }): JSX.Element {
  const initLanguage =
    (store.get(
      'dailyCodingChallengeLanguage'
    ) as DailyCodingChallengeLanguages) ?? 'javascript';

  const [isLoading, setIsLoading] = useState(true);
  const [challengeFound, setChallengeFound] = useState(false);
  const [challengeProps, setChallengeProps] =
    useState<null | DailyCodingChallengeDataFormatted>(null);
  const [dailyCodingChallengeLanguage, setDailyCodingChallengeLanguage] =
    useState<DailyCodingChallengeLanguages>(initLanguage);

  const fetchChallenge = async (date: string) => {
    try {
      const response = await fetch(
        `${apiLocation}/daily-coding-challenge/date/${date}`
      );
      const challengeData = await response.json();

      if (challengeData) {
        const validDailyCodingChallenge = validateDailyCodingChallengeSchema(
          challengeData as DailyCodingChallengeFromDb
        );

        if ('error' in validDailyCodingChallenge) {
          throw new Error(
            `Challenge data validation failed: ${validDailyCodingChallenge.error?.message || 'Unknown validation error'}`
          );
        }

        const formattedChallengeData = formatChallengeData(
          challengeData as DailyCodingChallengeFromDb
        ) as DailyCodingChallengeDataFormatted;

        setChallengeProps(formattedChallengeData);
        setChallengeFound(true);
      } else {
        setChallengeFound(false);
      }
    } catch (error) {
      setChallengeFound(false);
      console.error('Error fetching data:', error);
    } finally {
      setIsLoading(false);
    }
  };

  useEffect(() => {
    // If date is invalid, stop loading/fetching and show the not found page
    if (!date || !isValidDateString(date)) {
      setIsLoading(false);
      setChallengeFound(false);
      return;
    }

    void fetchChallenge(date);
  }, [date]);

  if (isLoading) return <Loader />;

  if (!challengeFound || !challengeProps)
    return <DailyCodingChallengeNotFound />;

  return (
    <ShowClassic
      isDailyCodingChallenge={true}
      dailyCodingChallengeLanguage={dailyCodingChallengeLanguage}
      setDailyCodingChallengeLanguage={setDailyCodingChallengeLanguage}
      {...challengeProps[dailyCodingChallengeLanguage]}
    />
  );
}

ShowDailyCodingChallenge.displayName = 'ShowDailyCodingChallenge';

export default ShowDailyCodingChallenge;
