'use client';

import { useRouter } from 'next/navigation';
import { type ChangeEvent, useContext, useEffect, useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useSWRConfig } from 'swr';

import AppLink from '@/components/ui/AppLink';
import { Button } from '@/components/ui/Button';
import Dialog from '@/components/ui/Dialog';
import { Icon, Icons } from '@/components/ui/Icon';
import { Input } from '@/components/ui/Input';
import Select from '@/components/ui/Select';

import { UserContext } from '@/context/user';
import { useGroups } from '@/lib/hooks/use-groups';
import { usePuzzles } from '@/lib/hooks/use-puzzles';
import type { Chapter, Puzzle } from '@/lib/puzzles';
import { cn } from '@/lib/utils';
import useLocalStorage from '@/lib/hooks/use-local-storage';

const difficulty = [
  { value: 'easy', label: 'Facile' },
  { value: 'medium', label: 'Moyen' },
  { value: 'hard', label: 'Difficile' }
];

// TODO: REFACTOR FILTER TO AVOID WARNINGS

export default function Puzzles({ token }: { token: string }) {
  const { data: me } = useContext(UserContext);
  const { data, isLoading } = usePuzzles({ token });
  const [isOpen, setIsOpen] = useState<boolean[]>([]);
  const [filterTags, setFilterTags] = useState<string>('');
  const [filterDifficulty, setFilterDifficulty] = useState<string>('');
  const [filterChapter, setFilterChapter] = useState<number>();

  function handleClick(index: number) {
    setIsOpen((prevState) => {
      const newState = [...prevState];
      newState[index] = !newState[index];
      return newState;
    });
  }

  function isInEventGroup(chapter: Chapter) {
    return (
      chapter.startDate &&
      chapter.endDate &&
      me?.groups?.some((group) => group.chapter && group.chapter === chapter.id)
    );
  }

  function isBeforeStart(chapter: Chapter) {
    if (!chapter.startDate || !chapter.endDate) {
      return false;
    }
    const startDate = new Date(chapter.startDate);
    const now = new Date();
    return now.getTime() < startDate.getTime() + 10 * 60 * 1000;
  }

  const filteredData = useMemo(() => {
    if ((filterTags || filterDifficulty) && filterChapter) {
      return data
        ?.find((chapter) => chapter.id === filterChapter)
        ?.puzzles.filter((puzzle) => {
          if (!puzzle?.tags) return false;
          if (filterDifficulty && filterTags) {
            if (filterTags === 'completed') {
              return puzzle!.tags!.some((tag) => tag.name === filterDifficulty) && puzzle!.score;
            } else if (filterTags === 'not-completed') {
              return puzzle!.tags!.some((tag) => tag.name === filterDifficulty) && !puzzle!.score;
            }
            return (
              puzzle!.tags!.some((tag) => tag.name === filterTags) &&
              puzzle!.tags!.some((tag) => tag.name === filterDifficulty)
            );
          }
          if (filterDifficulty) {
            return puzzle!.tags!.some((tag) => tag.name === filterDifficulty);
          }
          if (filterTags) {
            if (filterTags === 'completed') {
              return puzzle!.score;
            } else if (filterTags === 'not-completed') {
              return !puzzle!.score;
            }
            return puzzle!.tags!.some((tag) => tag.name === filterTags);
          }
          return puzzle;
        })
        .map((puzzle) => puzzle);
    }
    return data?.find((chapter) => chapter.id === filterChapter)?.puzzles;
  }, [data, filterTags, filterDifficulty, filterChapter]);

  return (
    <>
      {(!isLoading &&
        data?.map((chapter) => (
          <div key={chapter.id} className="flex flex-col">
            <div className="flex flex-col justify-between md:flex-row md:items-center">
              <div className="flex items-center gap-x-2">
                <h1 className="text-xl font-semibold">{chapter.name}</h1>
                {!isInEventGroup(chapter) && isBeforeStart(chapter) && (
                  <Dialog
                    key={chapter.id}
                    title={chapter.name}
                    open={isOpen[chapter.id]}
                    onOpenChange={() => handleClick(chapter.id)}
                    trigger={
                      <button className="flex items-center gap-x-2 text-sm font-semibold text-muted hover:text-brand">
                        {/* <Icon name="group-line" /> */}
                        Rejoindre un groupe
                      </button>
                    }
                    className="right-96 p-4"
                  >
                    <GroupForm chapter={chapter} token={token} />
                  </Dialog>
                )}
              </div>
              <div className="flex flex-col">
                {chapter.startDate && chapter.endDate ? (
                  <div className="flex items-center justify-start gap-x-2 md:justify-end">
                    {/* <Icon name="calendar-line" className="text-sm text-muted" /> */}
                    <span className="text-sm text-muted">
                      {new Date(chapter.startDate).toLocaleDateString('fr-FR', {
                        day: 'numeric',
                        month: 'long',
                        year: 'numeric',
                        hour: 'numeric',
                        minute: 'numeric'
                      })}{' '}
                      -{' '}
                      {new Date(chapter.endDate).toLocaleDateString('fr-FR', {
                        day: 'numeric',
                        month: 'long',
                        year: 'numeric',
                        hour: 'numeric',
                        minute: 'numeric'
                      })}
                    </span>
                  </div>
                ) : (
                  <div className="h-1 w-1/4 rounded-lg bg-gray-200">
                    <div className="h-1 w-1/2 rounded-lg bg-gradient-to-tl from-brand to-brand-accent" />
                  </div>
                )}
                <div className="mt-1 flex justify-start gap-x-2">
                  {isInEventGroup(chapter) && (
                    <>
                      <FilterDifficulty
                        chapters={data}
                        chapter={chapter}
                        filter={filterDifficulty}
                        setFilter={setFilterDifficulty}
                        setFilterChapter={setFilterChapter}
                      />
                      <FilterTags
                        chapters={data}
                        chapter={chapter}
                        filter={filterTags}
                        setFilter={setFilterTags}
                        setFilterChapter={setFilterChapter}
                      />
                    </>
                  )}
                </div>
              </div>
            </div>
            {isInEventGroup(chapter) && (
              <ul className="mt-4 flex flex-col space-y-4">
                {filteredData &&
                  filteredData
                    .sort((a, b) => a.scoreMax - b.scoreMax)
                    .map((puzzle) => (
                      <PuzzleProp key={puzzle.id} puzzle={puzzle} chapter={chapter} />
                    ))}
              </ul>
            )}
          </div>
        ))) || (
        <div className="flex flex-col space-y-6">
          {[...Array(3).keys()].map((i) => (
            <div key={i} className="flex flex-col space-y-4">
              <div className="flex items-center justify-between">
                <span className="inline-block h-8 w-1/2 rounded-lg bg-primary-600" />
                <span
                  className="inline-block h-1 w-1/4 animate-pulse rounded-lg bg-primary-600"
                  style={{
                    animationDelay: `${i * 0.05}s`,
                    animationDuration: '1s'
                  }}
                />
              </div>
              <ul className="flex flex-col space-y-4">
                {[...Array(6).keys()].map((j) => (
                  <span
                    key={j}
                    className="inline-block h-14 animate-pulse rounded-lg bg-primary-600"
                    style={{
                      animationDelay: `${j * 0.05}s`,
                      animationDuration: '1s'
                    }}
                  />
                ))}
              </ul>
            </div>
          ))}
        </div>
      )}
    </>
  );
}

function PuzzleProp({ puzzle, chapter }: { puzzle: Puzzle; chapter: Chapter }) {
  function isStarted(chapter: Chapter) {
    if (!chapter.startDate || !chapter.endDate) {
      return false;
    }
    const startDate = new Date(chapter.startDate);
    const now = new Date();
    return now > startDate;
  }
  return (
    <li
      className={cn(
        'group relative flex h-full w-full rounded-md border-2 bg-primary-700 font-code transition-colors duration-150 hover:bg-primary-600',
        {
          'border-green-600/30': puzzle.tags?.find((tag) => tag.name.toLowerCase() === 'easy'),
          'border-yellow-600/30': puzzle.tags?.find((tag) => tag.name.toLowerCase() === 'medium'),
          'border-red-600/30': puzzle.tags?.find((tag) => tag.name.toLowerCase() === 'hard'),
          'border-highlight-primary': !puzzle.tags?.length,
          'cursor-not-allowed': !isStarted(chapter)
        }
      )}
    >
      {isStarted(chapter) ? (
        <AppLink
          className="flex h-full w-full items-center justify-between p-4"
          key={puzzle.id}
          href={`/dashboard/puzzles/${puzzle.id}`}
        >
          <div className="flex w-10/12 flex-col gap-2 lg:w-full lg:flex-row">
            <span className="text-base font-semibold">
              {puzzle.name}{' '}
              <span className="text-sm text-highlight-secondary">
                ({puzzle.score ? `${puzzle.score}` : '?'}/{puzzle.scoreMax} points)
              </span>
            </span>
          </div>
          <div className="flex items-center gap-x-6">
            {puzzle.tags?.length && (
              <div className="flex gap-x-2 text-sm text-muted">
                {puzzle.tags
                  .filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name))
                  .map((tag, i) => (
                    <span key={i} className="inline-block rounded-md bg-primary-800 px-2 py-1">
                      {tag.name}
                    </span>
                  ))}
              </div>
            )}
            <Icon
              className="-translate-x-2 transform-gpu text-highlight-secondary duration-300 group-hover:translate-x-0 group-hover:text-brand"
              name="arrow-right-line"
            />
          </div>
        </AppLink>
      ) : (
        <div className="flex h-full w-full items-center justify-between p-4 opacity-50">
          <div className="flex w-10/12 flex-col gap-2 lg:w-full lg:flex-row">
            <span className="text-base font-semibold">
              {puzzle.name}{' '}
              <span className="text-sm text-highlight-secondary">
                ({puzzle.score ? `${puzzle.score}` : '?'}/{puzzle.scoreMax} points)
              </span>
            </span>
          </div>
          <div className="flex items-center gap-x-6">
            {puzzle.tags?.length && (
              <div className="flex gap-x-2 text-sm text-muted">
                {puzzle.tags
                  .filter((tag) => !['easy', 'medium', 'hard'].includes(tag.name))
                  .map((tag, i) => (
                    <span key={i} className="inline-block rounded-md bg-primary-900 px-2 py-1">
                      {tag.name}
                    </span>
                  ))}
              </div>
            )}
            {/* <Icon
              className="-translate-x-2 transform-gpu text-highlight-secondary duration-300 group-hover:translate-x-0"
              name="arrow-right-line"
            /> */}
          </div>
        </div>
      )}
    </li>
  );
}

function FilterDifficulty({
  chapters,
  chapter,
  filter,
  setFilter,
  setFilterChapter
}: {
  chapters: Chapter[];
  chapter: Chapter;
  filter: string;
  setFilter: (filter: string) => void;
  setFilterChapter: (chapter: number) => void;
}) {
  const [stored, setStored] = useLocalStorage({
    key: 'filter-difficulty',
    initialValue: ''
  });

  let options = [] as { title: string; value: string }[];

  options = chapters
    .find((c) => c.id === chapter.id)
    ?.puzzles?.map((p) => p.tags)
    .flat()
    .filter((tag) => difficulty.some((d) => tag?.name === d.value))
    .filter((tag, index, self) => self.findIndex((t) => t!.name === tag!.name) === index)
    .map((t) => {
      return { title: t!.name, value: t!.name };
    }) as { title: string; value: string }[];

  options?.unshift({ title: 'Toutes les difficultés', value: '' });

  setFilterChapter(chapter.id);

  function handleChange(event: ChangeEvent<HTMLSelectElement>) {
    setFilter(event.target.value);
    // TODO OPTI
    // @ts-ignore
    setStored(event.target.value);
  }

  useEffect(() => {
    if (stored) {
      // TODO OPTI
      // @ts-ignore
      setFilter(stored);
    }
  }, [stored]);

  return (
    <Select className="w-full sm:w-44" options={options} value={filter} onChange={handleChange} />
  );
}

function FilterTags({
  chapters,
  chapter,
  filter,
  setFilter,
  setFilterChapter
}: {
  chapters: Chapter[];
  chapter: Chapter;
  filter: string;
  setFilter: (filter: string) => void;
  setFilterChapter: (chapter: number) => void;
}) {
  const [stored, setStored] = useLocalStorage({
    key: 'filter-tags',
    initialValue: ''
  });

  let options = [] as { title: string; value: string }[];

  options = chapters
    .find((c) => c.id === chapter.id)
    ?.puzzles?.map((p) => p.tags)
    .flat()
    .filter((tag) => !difficulty.some((d) => tag?.name === d.value))
    .filter((tag, index, self) => self.findIndex((t) => t!.name === tag!.name) === index)
    .map((t) => {
      return { title: t!.name, value: t!.name };
    }) as { title: string; value: string }[];

  options?.unshift({ title: 'Pas encore terminé(s)', value: 'not-completed' });
  options?.unshift({ title: 'Terminé(s)', value: 'completed' });
  options?.unshift({ title: 'Tout les puzzles', value: '' });

  setFilterChapter(chapter.id);

  function handleChange(event: ChangeEvent<HTMLSelectElement>) {
    setFilter(event.target.value);
    // TODO OPTI
    // @ts-ignore
    setStored(event.target.value);
  }

  useEffect(() => {
    if (stored) {
      // TODO OPTI
      // @ts-ignore
      setFilter(stored);
    }
  }, [stored]);

  return (
    <Select className="w-full sm:w-44" options={options} value={filter} onChange={handleChange} />
  );
}

type GroupData = {
  name?: string;
  chapter?: number;
  puzzle?: number;
};

function GroupForm({ chapter, token }: { chapter: Chapter; token: string }) {
  const [isJoining, setIsJoining] = useState(false);

  const { data: groups } = useGroups({ token });
  const { mutate } = useSWRConfig();

  const router = useRouter();

  const { register, handleSubmit, reset } = useForm<GroupData>({
    defaultValues: {
      name: undefined,
      chapter: chapter.id,
      puzzle: undefined
    }
  });

  async function onSubmit(data: GroupData) {
    const res = await fetch(
      `${process.env.NEXT_PUBLIC_API_URL}/${isJoining ? 'groupJoin' : 'groupCreate'}`,
      {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {
          Authorization: `Bearer ${token}`
        }
      }
    );

    if (res.ok) {
      mutate('me');
      // TODO REFACTOR
      router.refresh();
    }
  }

  return (
    <div className="flex flex-col">
      <div className="flex justify-between">
        <button
          onClick={() => {
            setIsJoining(false);
            reset();
          }}
          className={cn('rounded-lg p-2 font-semibold', {
            'bg-primary-500': !isJoining
          })}
        >
          Créer un groupe
        </button>
        <button
          onClick={() => {
            setIsJoining(true);
            reset();
          }}
          className={cn('rounded-lg p-2 font-semibold', {
            'bg-primary-500': isJoining
          })}
        >
          Rejoindre un groupe
        </button>
      </div>
      <div className="px-2 py-4">
        <hr className="border-primary-600" />
      </div>
      <form
        className="flex w-full flex-col justify-between"
        onSubmit={handleSubmit(onSubmit)}
        encType="multipart/form-data"
      >
        <div className="flex w-56 flex-col space-y-4">
          {!isJoining ? (
            <>
              <div className="flex flex-col">
                <Input
                  className="w-full"
                  // label="Nom du groupe"
                  type="text"
                  placeholder="Terre en vue mon capitaine !"
                  required
                  {...register('name', {
                    pattern: {
                      value: /^[a-zA-Z0-9À-ÿ\s_-]{3,20}$/,
                      message: 'Le nom doit contenir entre 3 et 20 caractères'
                    }
                  })}
                />
              </div>
            </>
          ) : (
            <>
              <Select
                className="w-full"
                label="Groupes disponibles"
                required
                {...register('name')}
                options={
                  groups
                    ?.filter((group) => group.chapter === chapter.id)
                    .map((group) => ({
                      title: group.name,
                      value: group.name
                    })) || []
                }
              />
            </>
          )}
          <Button type="submit">{isJoining ? 'Rejoindre' : 'Créer'}</Button>
        </div>
      </form>
    </div>
  );
}
