'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 './AppLink';
import Button from './Button';
import Dialog from './Dialog';
import Icon from './Icon';
import Input from './Input';
import Select from './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';

export default function Puzzles({ token }: { token: string }) {
  const { data: me } = useContext(UserContext);
  const { data, isLoading } = usePuzzles({ token });
  const [isOpen, setIsOpen] = useState<boolean[]>([]);
  const [filter, setFilter] = 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)
    );
  }

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

  useEffect(() => {
    const { hash } = window.location;
    if (hash) {
      const element = document.querySelector(hash);
      if (element) {
        element.scrollIntoView({ behavior: 'smooth' });
      }
    }
  }, []);

  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) && (
                  <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 gap-x-2">
                    <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'
                      })}{' '}
                      -{' '}
                      {new Date(chapter.endDate).toLocaleDateString('fr-FR', {
                        day: 'numeric',
                        month: 'long',
                        year: 'numeric',
                        hour: '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-end">
                  {isInEventGroup(chapter) && (
                    <FilterChapter
                      chapters={data}
                      chapter={chapter}
                      filter={filter}
                      setFilter={setFilter}
                      setFilterChapter={setFilterChapter}
                    />
                  )}
                </div>
              </div>
            </div>
            {isInEventGroup(chapter) && (
              <ul className="mt-4 flex flex-col space-y-4">
                {filteredData &&
                  filteredData
                    .sort((p1, p2) => {
                      const p1Tags = p1.tags || [];
                      const p2Tags = p2.tags || [];
                      const p1Easy = p1Tags.some((tag) => tag.name === 'easy');
                      const p2Easy = p2Tags.some((tag) => tag.name === 'easy');
                      if (p1Easy !== p2Easy) {
                        return p1Easy ? -1 : 1;
                      }
                      const p1Medium = p1Tags.some((tag) => tag.name === 'medium');
                      const p2Medium = p2Tags.some((tag) => tag.name === 'medium');
                      if (p1Medium !== p2Medium) {
                        return p1Medium ? -1 : 1;
                      }
                      const p1Hard = p1Tags.some((tag) => tag.name === 'hard');
                      const p2Hard = p2Tags.some((tag) => tag.name === 'hard');
                      if (p1Hard !== p2Hard) {
                        return p1Hard ? -1 : 1;
                      }
                      return p1Tags.length - p2Tags.length;
                    })
                    .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 }) {
  const isPuzzleAvailable = (chapter: Chapter) => {
    const today = new Date();
    const startDate = new Date(chapter.startDate!);
    const endDate = new Date(chapter.endDate!);
    return (
      (chapter.startDate && chapter.endDate && today >= startDate && today <= endDate) ||
      (!chapter.startDate && !chapter.endDate)
    );
  };
  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': !isPuzzleAvailable(chapter)
        }
      )}
    >
      {isPuzzleAvailable(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>
            {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>
            )}
          </div>
          <Icon
            className="-translate-x-2 transform-gpu duration-300 group-hover:translate-x-0"
            name="arrow-right-line"
          />
        </AppLink>
      ) : (
        <div className="flex h-full w-full items-center justify-between p-4 opacity-50">
          <div className="flex gap-x-2">
            <span className="text-base font-semibold">
              {puzzle.name} ({puzzle.scoreMax})
            </span>
            {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={cn('inline-block rounded-md bg-primary-900 px-2 py-1')}
                    >
                      {tag.name}
                    </span>
                  ))}
              </div>
            )}
          </div>
        </div>
      )}
    </li>
  );
}

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

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

  options = chapters
    .find((c) => c.id === chapter.id)
    ?.puzzles?.map((p) => p.tags)
    .flat()
    .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: 'no-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-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) {
    await fetch(`${process.env.NEXT_PUBLIC_API_URL}/${isJoining ? 'groupJoin' : 'groupCreate'}`, {
      method: 'POST',
      body: JSON.stringify(data),
      headers: {
        Authorization: `Bearer ${token}`
      }
    });
    // TODO: handle errors
    // if (res.ok) {
    //   if (!isJoining) {
    //     mutate('groups');
    //   } else {
    //     mutate('me');
    //   }
    //   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')}
                />
              </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 kind="brand" type="submit">
            {isJoining ? 'Rejoindre' : 'Créer'}
          </Button>
        </div>
      </form>
    </div>
  );
}
